我正在尝试构建一个显示用户健康数据的watchOS 2复杂功能,例如步骤(但理论上它应该能够显示用户已授予应用权限查看的任何健康数据)。当复杂化首次启动时,我可以查询Healthkit并获取我想要的所有数据,因为第一次启动被认为是在前台。但是,当新的健康数据可用时,我在后台检索HealthKit数据时遇到问题。我可以通过两个地方获得这些数据,手表和iPhone。
当从getNextRequestedUpdateDateWithHandler中设置的日期触发并发症的后台刷新时,我试图从手表中获取数据。但是,当我调用HKHealthStore的execute方法时,如果应用程序(或者在这种情况下是复杂的)运行后台,它不会返回任何查询结果。我还尝试设置一个HKAnchoredObject查询,该查询应该在进程恢复时立即返回我的结果,但除非我在手表上手动启动应用程序扩展,否则这似乎也不会返回任何结果。这是我的监视代码,在请求运行状况工具包权限后从我的ExtensionDelegate的init方法调用:
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)
}
}
我还尝试使用HKObserverQuery从iPhone获取数据。我有观察者查询,可以每小时唤醒一次iPhone(步骤数据的最大时间)。但是,如果在观察者完成处理程序执行我的步骤查询时iPhone被锁定,则HKHealthStore的execute方法也拒绝返回任何查询结果。我认为这在这里是有道理的,并且可能没有办法解决这个问题,因为Apple's docs提到当设备被锁定而您无法从商店中读取时(仅写入),Health Store会被加密。但是在手表的情况下,当它在某人的手腕上没有锁定时,屏幕就会关闭。
有没有人知道如何在后台进行刷新时,在iOS或watchOS 2上让HealthKit更新显示在并发症上?
答案 0 :(得分:7)
经过大量测试后,我确定目前无法做到这一点。在watchOS 2上,当在后台运行扩展或并发症时,Apple似乎已完全禁用HealthKit查询返回结果。这包括从远程通知,Watch Connectivity以及复杂计划刷新执行。如果屏幕关闭且设备设置了密码,iPhone的HealthKit查询将失败。查询失败,因为在锁定设备时加密了运行状况数据存储。即使启用了观察者查询和后台传递,查询也会失败。您可以收到有关更改内容的通知,但在iPhone解锁之前您无法查询更改(因为数据已加密)。
显示健康套件相关数据的其他应用程序,例如步数和步行+跑步距离,通过直接查询计步器(CMPedometer)来实现,这些数据可在这些背景模式下访问。
对于没有在其设备上设置密码的iPhone用户而言,可能会产生一种复杂的背景更新,但这似乎是一个可怕的想法。