2014-12-21 4 views
14

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

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

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

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

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

Я взял свой образец кода и модифицировать его так, что он дает мне местное уведомление, а не отправлять данные на сервер (так как у меня нет сервера). Он работает, но я сделал несколько других изменений, поэтому я не знаю, какие из них необходимы. Изменения, которые я сделал, - избавиться от всех dispatch_async в главной очереди. Установите предикат только для выполнения сегодняшних шагов (для получения всех шагов потребовалось много времени).Перемещенный вызов completeHandler() в конец 'resultsHandler' в' getQuantityResult' - так, что он вызывается, как только вся обработка завершена – Paulw11

+0

Привет, Paulw11, спасибо за ваш ответ. Вы уверены, что получаете результаты в фоновом режиме, например, еще через 1 час? Мы получаем результаты, но только за 1-2 минуты, потом ничего. Как насчет тебя? – Oakleaf

+0

Хм, это странно, мы можем заставить его работать в симуляторе, но не на физическом устройстве iPhone. У нас заканчиваются подсказки, кто-нибудь знает, что искать? Так как он работает в симуляторе. – Oakleaf

ответ

0

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

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

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

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

Edit: После принятия второго взгляда на документах

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

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

HKObserverQuery Reference

5

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

ПРИМЕЧАНИЕ

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

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