You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 14:33:03