如何在后台刷新的并发症上显示 HealthKit 数据?

How can you display HealthKit data on a complication that is refreshed in the background?

我正在尝试构建一个 watchOS 2 复杂功能来显示用户的健康数据,例如步数(但理论上它应该能够显示用户授予应用程序查看权限的任何健康数据)。当并发症首次启动时,我可以查询 Healthkit 并获取我想要的所有数据,因为第一次启动被认为是在前台。但是,当有新的健康数据可用时,我无法在后台检索 HealthKit 数据。我可以在两个地方获取这些数据,watch 和 iPhone.

当从 getNextRequestedUpdateDateWithHandler 中设置的日期触发并发症的后台刷新时,我试图从手表本身获取数据。但是,当我调用 HKHealthStore 的执行方法时,如果应用程序(或在本例中为并发症)是 运行 后台,它不会 return 任何查询结果。我还尝试设置一个 HKAnchoredObject 查询,该查询应该在进程恢复时立即 return 我的结果,但这似乎也不会 return 任何结果,除非我在手表上手动启动应用程序扩展。这是我的手表代码,在请求健康工具包权限后从我的 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 的执行方法也会拒绝 return 任何查询结果。我认为这在这里是有道理的,可能没有办法解决这个问题,因为 Apple's docs 提到当设备被锁定并且您无法从商店读取(只能写入)时,Health Store 是加密的。但是在手表的情况下,当它在某人的手腕上时它没有被锁定,屏幕只是关闭了。

有谁知道如何在 iOS 或 watchOS 2 中在后台发生刷新时让 HealthKit 更新显示在并发症上?

经过大量测试后,我确定目前这是不可能的。在 watchOS 2 上,Apple 似乎已完全禁止 HealthKit 查询在后台运行扩展程序或复杂功能时返回结果。运行ning。这包括从远程通知、Watch Connectivity 和并发症计划刷新执行。如果屏幕关闭且设备设置了密码,iPhone 的 HealthKit 查询将失败。查询失败,因为健康数据存储在设备锁定时被加密。即使启用了观察者查询和后台交付,查询也会失败。您可以收到有关更改的通知,但是在 iPhone 解锁之前您无法查询更改(因为数据再次被加密)。

其他显示 healthkit 相关数据的应用程序,例如步数和步行+运行 距离,通过直接查询计步器 (CMPedometer) 来实现,其数据可在这些后台模式下访问。

有人可能会在后台为 iPhone 未在其设备上设置密码的用户专门更新,但这似乎是一个糟糕的推广想法。