4

Я пытаюсь создать сложную процедуру watchOS 2, которая отображает данные о работоспособности пользователя, такие как шаги (но теоретически она должна иметь возможность отображать любые данные о состоянии здоровья, которые пользователь предоставил для просмотра приложения). Когда первое запущенное осложнение, я могу запросить Healthkit и получить все нужные данные, потому что первый запуск считается находящимся на переднем плане. Однако у меня возникают проблемы с извлечением данных HealthKit в фоновом режиме, когда доступны новые данные о состоянии здоровья. Есть два места, где я могу получить эти данные, часы и iPhone.Как вы можете отображать данные HealthKit об осложнениях, которые обновляются в фоновом режиме?

Я попытался получить данные из самих часов, когда обновление фона осложнения запускается с даты, установленной в getNextRequestedUpdateDateWithHandler. Однако, когда я вызываю метод выполнения HKHealthStore, он не возвращает никаких результатов запроса, если приложение (или в этом случае усложнение) работает с фоном. Я также пытался настроить запрос HKAnchoredObject, который должен немедленно возвращать мои результаты, когда процесс возобновляется, но это также, похоже, не возвращает никаких результатов, если я вручную не запустил расширение приложения на часах. Вот мои часы код, вызывается из метода инициализации моего ExtensionDelegate после разрешения набора здоровья запрашиваются:

func setupComplicationDataCache() { 
    let now = NSDate() 
    var startDate: NSDate? = nil 
    var interval: NSTimeInterval = 0 

    self.calendar.rangeOfUnit(NSCalendarUnit.Day, startDate: &startDate, interval: &interval, forDate: now) 
    let stepSampleType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)! 

    // Match samples with a start date after the workout start 
    let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: nil, options: .None) 
    let query = HKAnchoredObjectQuery(type: stepSampleType, predicate: predicate, anchor: nil, limit: 0) { (query, samples, deletedObjects, anchor, error) -> Void in 
     // Handle when the query first returns results 
     self.handleStepResults(query, samples: samples, deletedObjects: deletedObjects, anchor: anchor, error: error) 
    } 

    query.updateHandler = { (query, samples, deletedObjects, anchor, error) -> Void in 
     // Handle update notifications after the query has initially run 
     self.handleStepResults(query, samples: samples, deletedObjects: deletedObjects, anchor: anchor, error: error) 
    } 

    self.healthStore.executeQuery(query); 
} 

func handleStepResults(query: HKAnchoredObjectQuery, samples: [HKSample]?, deletedObjects: [HKDeletedObject]?, anchor: HKQueryAnchor?, error: NSError?) { 
    if error != nil { 
     self.timelineModel.currentEntry = TimelineEntryModel(value: NSNumber(int: -1), endDate: NSDate()) 
    } else if samples == nil || samples?.count == 0 { 
     self.timelineModel.currentEntry = TimelineEntryModel(value: NSNumber(int: 0), endDate: NSDate()) 
    } else { 
     let newStepSamples = samples as! [HKQuantitySample] 
     var stepCount = self.timelineModel.currentEntry.value.doubleValue 
     var currentDate = self.timelineModel.currentEntry.endDate 

     // Add the current entry to the collection of past entries 
     self.timelineModel.pastEntries.append(self.timelineModel.currentEntry) 

     // Add all new entries to the collection of past entries 
     for result in newStepSamples { 
      stepCount += result.quantity.doubleValueForUnit(self.countUnit) 
      currentDate = result.endDate 
      self.timelineModel.pastEntries.append(TimelineEntryModel(value: NSNumber(double: stepCount), endDate: currentDate)) 
     } 

     // Retrieve the latest sample as the current item 
     self.timelineModel.currentEntry = self.timelineModel.pastEntries.popLast() 
     if self.timelineModel.currentEntry == nil { 
      self.timelineModel.currentEntry = TimelineEntryModel(value: NSNumber(int: -3), endDate: NSDate()) 
     } 
    } 

    // Reload the complication 
    let complicationServer = CLKComplicationServer.sharedInstance() 
    for complication in complicationServer.activeComplications { 
     complicationServer.reloadTimelineForComplication(complication) 
    } 
} 

Я также пытался получить данные из iPhone с помощью HKObserverQuery. У меня есть запрос наблюдателя, который может разбудить iPhone один раз в час (максимальное время для данных шага). Однако, если iPhone заблокирован, когда обработчик завершения наблюдателя выполняет мой запрос шага, метод выполнения HKHealthStore также отказывается возвращать любые результаты запроса. Я думаю, что это имеет смысл здесь, и, вероятно, это не так, потому что Apple's docs упоминает, что магазин здоровья зашифрован, когда устройство заблокировано, и вы не можете читать из магазина (только писать). НО в случае с часами, когда он у кого-то запястья, он не заблокирован, экран просто выключен.

Кто-нибудь знает, как получить обновления HealthKit для выявления осложнений, когда обновление происходит в фоновом режиме, либо в iOS, либо на watchOS 2?

+0

Какую ставку вы пытались использовать при выполнении обновлений осложнений на часах? – Cobra

+0

Это не имело значения. Я пробовал 30 минут и 1 час, оба из которых были в порядке, без использования запросов HealthKit. – lehn0058

ответ

7

После тщательного тестирования я решил, что в настоящее время это невозможно. На watchOS 2 Apple, похоже, полностью отключила запросы HealthKit от возвращения результатов, когда расширение или осложнение работают в фоновом режиме. Это включает в себя выполнение удаленных уведомлений, Watch Connectivity и из запланированного обновления осложнений. Запросы HealthKit от iPhone терпят неудачу, если экран выключен, а устройство имеет набор кодов доступа. Запросы терпят неудачу, потому что хранилище данных работоспособности зашифровывается, когда устройство заблокировано. Запросы терпят неудачу, даже если запросы наблюдателей и доставка фона включены. Вы можете получить уведомление о том, что что-то изменилось, но вы не можете запрашивать изменения до тех пор, пока iPhone не будет разблокирован (потому что снова данные зашифрованы).

Другие приложения, которые показывают данные, относящиеся к здоровью, например, шаги и пройденное расстояние + пробег делают это, напрямую запрашивая шагомер (CMPedometer), данные которого доступны в этих фоновых режимах.

Возможно, возникло осложнение, которое обновляется в фоновом режиме эксклюзивно для пользователей iPhone, у которых нет пароля, установленного на их устройстве, но это кажется ужасной идеей для продвижения.