HealthKit (iOS) не предоставляет данные в фоновом режиме (objC)

В настоящее время мы пытаемся заставить HealthKit работать в фоновом режиме, чтобы доставлять данные шагов на наш сервер, когда приложение закрыто.

Для экспериментальных целей мы создали новый проект iOS в XCode, включили HealhtKit и все фоновые режимы в Compabilities. После этого мы в значительной степени запускаем код (см. Далее).

Итак, что происходит первым, так это то, что приложение thecourse запрашивает разрешения, которые мы предоставляем. Мы ожидаем, что приложение должно постоянно доставлять данные шагов каждый час на сервер. Но он этого не делает, кажется, что приложение не может ничего делать, когда оно неактивно.

Приложение только доставляет данные, когда оно возобновляется или запускается, но вовсе не с фона (Soft-closed/Hard-closed)

appdelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self setTypes];
    return YES;
}


-(void) setTypes
{
    self.healthStore = [[HKHealthStore alloc] init];

    NSMutableSet* types = [[NSMutableSet alloc]init];
    [types addObject:[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]];

    [self.healthStore requestAuthorizationToShareTypes: types
                                             readTypes: types
                                            completion:^(BOOL success, NSError *error) {

                                                dispatch_async(dispatch_get_main_queue(), ^{
                                                    [self observeQuantityType];
                                                    [self enableBackgroundDeliveryForQuantityType];
                                                });
                                            }];
}

-(void)enableBackgroundDeliveryForQuantityType{
    [self.healthStore enableBackgroundDeliveryForType: [HKQuantityType quantityTypeForIdentifier: HKQuantityTypeIdentifierStepCount] frequency:HKUpdateFrequencyImmediate withCompletion:^(BOOL success, NSError *error) {
    }];
}


-(void) observeQuantityType{

    HKSampleType *quantityType = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];

    HKObserverQuery *query =
    [[HKObserverQuery alloc]
     initWithSampleType:quantityType
     predicate:nil
     updateHandler:^(HKObserverQuery *query,
                     HKObserverQueryCompletionHandler completionHandler,
                     NSError *error) {

         dispatch_async(dispatch_get_main_queue(), ^{
             if (completionHandler) completionHandler();
             [self getQuantityResult];

         });
     }];
    [self.healthStore executeQuery:query];
}


-(void) getQuantityResult{

    NSInteger limit = 0;
    NSPredicate* predicate = nil;

    NSString *endKey =  HKSampleSortIdentifierEndDate;
    NSSortDescriptor *endDate = [NSSortDescriptor sortDescriptorWithKey: endKey ascending: NO];

    HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType: [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]
                                                           predicate: predicate
                                                               limit: limit
                                                     sortDescriptors: @[endDate]
                                                      resultsHandler:^(HKSampleQuery *query, NSArray* results, NSError *error){

                                                          dispatch_async(dispatch_get_main_queue(), ^{
                                                                // sends the data using HTTP
                                                              [self sendData: [self resultAsNumber:results]];

                                                          });
                                                      }];
    [self.healthStore executeQuery:query];
}

Ответы

Ответ 1

Я вижу что-то, что может вызвать проблему в вашем AppDelegate, особенно в этой строке:

[[NSURLConnection alloc] initWithRequest:request delegate:self];

Это создает NSURLConnection, но не запускает его. Попробуйте изменить его на это:

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];

Изменить: после второго взгляда на документы

Они рекомендуют настраивать ваши запросы наблюдателей в вашем методе application didFinishLaunchingWithOptions:. В приведенном выше коде вы устанавливаете HKObserverQuery вверх в обработчике авторизации, который вызывается в случайной фоновой очереди. Попробуйте сделать это изменение, чтобы настроить его на основной поток:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self setTypes];
    [self observeQuantityType];
    return YES;
}

Справочник HKObserverQuery

Ответ 2

Я узнал об этом некоторое время назад, когда говорил с кем-то из Apple. По-видимому, вы не можете получить доступ к данным HK в фоновом режиме, если устройство заблокировано:

Примечание

Поскольку хранилище HealthKit зашифровано, ваше приложение не может читать данные из магазина, когда телефон заблокирован. Это означает, что ваше приложение не может иметь доступ к магазину, когда он запускается в фоновом режиме. Однако приложения могут записывать данные в магазин, даже если телефон заблокирован. Хранилище временно кэширует данные и сохраняет их на зашифрованный магазин, как только телефон разблокируется.

от: https://developer.apple.com/library/ios/documentation/HealthKit/Reference/HealthKit_Framework/