如何从Health App实时获取心率数据?可使用HKObserverQuery实现吗?
解答
核心结论
- 你完全可以通过
HKObserverQuery实现心率数据的实时监听,不需要重启应用就能自动获取最新的心率记录 - 你当前的代码仅实现了单次心率拉取逻辑,没有设置数据变更监听,所以只能在启动时拿到一次数据
实现逻辑
HKObserverQuery是HealthKit专门提供的用于监听指定类型数据变动的查询类,你可以给心率数据类型注册一个ObserverQuery,后续只要Health App中有新的心率记录写入,系统就会自动触发你预设的回调,你在回调中重新执行拉取最新心率的逻辑即可。
注意事项
- 需要把创建的
HKObserverQuery作为类的属性持有,否则查询会被ARC自动释放,后续不会触发回调 - 你原有代码中存在两处笔误/逻辑错误:一是
latestHarteRate方法里把查询执行语句healthStore?.execute(query)写在了HKSampleQuery的回调闭包内部,导致查询永远不会被执行;二是方法名latestHarteRate拼写错误(应为latestHeartRate)
修正后的完整代码
import Foundation import UIKit import HealthKit class HealthStore { var healthStore: HKHealthStore? // 持有ObserverQuery,避免被释放 var heartRateObserverQuery: HKObserverQuery? init() { if HKHealthStore.isHealthDataAvailable(){ healthStore = HKHealthStore() } } func requestAuthorization(completion: @escaping (Bool) -> Void){ let heartBeat = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)! guard let healthStore = self.healthStore else { return completion(false) } healthStore.requestAuthorization(toShare: [], read: [heartBeat]) { (success, error) in completion(success) } } func latestHeartRate(){ guard let sampleType = HKObjectType.quantityType(forIdentifier: .heartRate), let healthStore = self.healthStore else { return } let startDate = Calendar.current.date(byAdding: .month, value: -1, to: Date()) let predicate = HKQuery.predicateForSamples(withStart: startDate, end: Date(), options: .strictEndDate) // 只需要拿最新1条数据,不需要拉取全量 let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false) let query = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: 1, sortDescriptors: [sortDescriptor]) { (sample, result, error) in guard error == nil, let result = result, let data = result.first as? HKQuantitySample else { return } let unit = HKUnit(from: "count/min") let latestHr = data.quantity.doubleValue(for: unit) print("Latest Hr \(latestHr) BPM") // 此处可添加自定义回调/通知,把心率数据传递给业务层 } // 执行查询的逻辑要移到闭包外部 healthStore.execute(query) } // 开启心率实时监听的方法,授权成功后调用即可 func startHeartRateObserver() { guard let heartRateType = HKObjectType.quantityType(forIdentifier: .heartRate), let healthStore = self.healthStore else { return } // 创建ObserverQuery heartRateObserverQuery = HKObserverQuery(sampleType: heartRateType, predicate: nil) { [weak self] query, completionHandler, error in guard error == nil else { completionHandler() return } // 检测到新的心率数据,重新拉取最新值 self?.latestHeartRate() completionHandler() } // 执行监听查询 healthStore.execute(heartRateObserverQuery!) // 开启后台更新权限,应用在后台时也能收到数据变动通知 healthStore.enableBackgroundDelivery(for: heartRateType, frequency: .immediate) { success, error in if success { print("心率后台更新已开启") } } } }
使用方式
在用户完成HealthKit授权之后,调用startHeartRateObserver()方法即可开启实时监听,后续有新的心率数据写入时会自动触发latestHeartRate()方法拉取最新值。
内容的提问来源于stack exchange,提问作者Manofsun
相关产品推荐
相关产品推荐

