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

在Swift中从Apple Watch获取实时心率(按钮触发,非后台运行)

Apple Watch 实时心率数据获取(按钮触发式)

以下是实现按钮触发式Apple Watch实时心率采集的分步方案:

1. 配置健康权限

首先需要在iOS和watchOS的Info.plist中添加健康数据访问权限描述:

  • 添加NSHealthReadUsageDescription键,值为应用读取心率数据的用途说明(例如:"获取实时心率数据用于健康状态监测")
  • 若你的应用还涉及写入健康数据,需额外添加NSHealthShareUsageDescription键(本场景仅读取可忽略)

2. 引入HealthKit框架

在watchOS应用的目标中,确保已添加HealthKit框架(Xcode中可通过Build Phases -> Link Binary With Libraries添加)。

3. 核心代码实现

初始化HealthStore与权限检查

import HealthKit
import WatchKit

class HeartRateController: WKInterfaceController {
    private let healthStore = HKHealthStore()
    private var activeHeartRateQuery: HKQuery?
    @IBOutlet weak var heartRateDisplayLabel: WKInterfaceLabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        checkHealthKitAvailabilityAndPermissions()
    }
    
    private func checkHealthKitAvailabilityAndPermissions() {
        guard HKHealthStore.isHealthDataAvailable() else {
            heartRateDisplayLabel.setText("设备不支持HealthKit")
            return
        }
        
        guard let heartRateType = HKObjectType.quantityType(forIdentifier: .heartRate) else {
            heartRateDisplayLabel.setText("心率数据类型不可用")
            return
        }
        
        let readPermissions: Set<HKObjectType> = [heartRateType]
        healthStore.requestAuthorization(toShare: nil, read: readPermissions) { [weak self] success, error in
            DispatchQueue.main.async {
                if let error = error {
                    self?.heartRateDisplayLabel.setText("权限请求失败: \(error.localizedDescription)")
                } else if !success {
                    self?.heartRateDisplayLabel.setText("未授权访问心率数据")
                }
            }
        }
    }
}

按钮触发的心率采集与停止

// 开始监测按钮点击事件
@IBAction func startMonitoringTapped() {
    guard let heartRateType = HKObjectType.quantityType(forIdentifier: .heartRate) else {
        heartRateDisplayLabel.setText("心率类型不可用")
        return
    }
    
    // 停止已有查询,避免重复监听
    if let query = activeHeartRateQuery {
        healthStore.stop(query)
    }
    
    // 创建锚定查询,获取最新心率并监听实时更新
    let anchorQuery = HKAnchoredObjectQuery(
        type: heartRateType,
        predicate: nil,
        anchor: nil,
        limit: HKObjectQueryNoLimit
    ) { [weak self] _, samples, _, _, error in
        self?.handleHeartRateSamples(samples)
    }
    
    // 设置更新回调,接收实时新增的心率数据
    anchorQuery.updateHandler = { [weak self] _, samples, _, _, error in
        self?.handleHeartRateSamples(samples)
    }
    
    activeHeartRateQuery = anchorQuery
    healthStore.execute(anchorQuery)
    heartRateDisplayLabel.setText("正在监测心率...")
}

// 停止监测按钮点击事件
@IBAction func stopMonitoringTapped() {
    if let query = activeHeartRateQuery {
        healthStore.stop(query)
        activeHeartRateQuery = nil
        heartRateDisplayLabel.setText("已停止监测")
    }
}

// 处理心率数据并更新UI
private func handleHeartRateSamples(_ samples: [HKSample]?) {
    guard let heartRateSamples = samples as? [HKQuantitySample],
          let latestSample = heartRateSamples.last else {
        return
    }
    
    DispatchQueue.main.async { [weak self] in
        // 转换心率单位为次/分钟(BPM)
        let bpmUnit = HKUnit.count().unitDivided(by: HKUnit.minute())
        let heartRate = latestSample.quantity.doubleValue(for: bpmUnit)
        self?.heartRateDisplayLabel.setText("当前心率: \(Int(heartRate)) BPM")
    }
}

4. 关键注意事项

  • UI更新必须在主线程:HealthKit的查询回调运行在后台线程,更新Watch UI时务必切换到主线程。
  • 避免重复查询:每次启动新的监测前,停止之前的active查询,防止资源浪费和重复数据回调。
  • 权限状态检查:用户可能在设置中随时撤销权限,建议在每次触发监测前再次检查权限状态。
  • 无后台需求适配:本方案仅在用户点击按钮后启动监测,停止后即终止查询,无需配置任何后台模式,完全符合你的需求。

内容的提问来源于stack exchange,提问作者Thomas Dini

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 20:55:21