Как вы можете отобразить данные HealthKit об осложнениях, которые обновляются в фоновом режиме?
Я пытаюсь создать услугу watchOS 2, которая отображает данные о работоспособности пользователя, такие как шаги (но теоретически она должна иметь возможность отображать любые данные о работоспособности, которые пользователь предоставил приложению для просмотра). Когда сложность начинается впервые, я могу запросить Healthkit и получить все данные, которые мне нужны, потому что первый запуск считается на переднем плане. Однако у меня возникают проблемы с извлечением данных HealthKit в фоновом режиме, когда доступны новые данные о работоспособности. Есть два места, где я мог бы получить эти данные, часы и iPhone.
Я пытался получить данные от самих часов, когда обновление фона осложнения запускается с даты, установленной в getNextRequestedUpdateDateWithHandler. Однако когда я вызываю метод execute из HKHealthStore, он не возвращает никаких результатов запроса, если приложение (или в этом случае осложнение) работает в фоновом режиме. Я также пытался настроить запрос HKAnchoredObject, который должен возвращать мои результаты сразу же после возобновления процесса, но, похоже, он также не возвращает никаких результатов, если я не запустил расширение приложения вручную. Вот мой код наблюдения, который вызывается из метода init моего 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 заблокирован, когда обработчик завершения наблюдателя выполняет мой шаговый запрос, метод execute HKHealthStore также отказывается возвращать результаты любого запроса. Я думаю, что это имеет смысл здесь, и, вероятно, нет никакого способа обойти это, потому что в документах Apple упоминается, что Магазин Здоровья зашифрован, когда устройство заблокировано, и вы не можете читать из магазина (только запись). НО в корпусе часов, когда он на чьем-то запястье, он не заблокирован, экран просто выключен.
Кто-нибудь знает, как заставить обновления HealthKit отображаться при возникновении осложнений, когда обновление происходит в фоновом режиме, либо в iOS, либо в watchOS 2?
1 ответ
После обширного тестирования я решил, что это в настоящее время невозможно. В watchOS 2 Apple, похоже, полностью отключила запросы HealthKit для возврата результатов, когда расширение или сложность выполняются в фоновом режиме. Это включает в себя выполнение из удаленных уведомлений, Watch Connectivity и из запланированного обновления осложнений. Запросы HealthKit iPhone не выполняются, если экран выключен и на устройстве установлен пароль. Запросы не выполняются, поскольку хранилище данных о работоспособности зашифровано, когда устройство заблокировано. Запросы не выполняются, даже если включены запросы наблюдателей и фоновая доставка. Вы можете получить уведомление о том, что что-то изменилось, но вы не можете запросить изменения, пока iPhone не будет разблокирован (потому что данные снова зашифрованы).
Другие приложения, которые отображают данные, относящиеся к аптечке, такие как шаги и пройденное расстояние, делают это путем прямого запроса шагомера (CMPedometer), данные которого доступны в этих фоновых режимах.
Можно было бы усложнить то, что обновления в фоновом режиме исключительно для пользователей iPhone, у которых не установлен пароль на их устройстве, но это кажется ужасной идеей для продвижения.