Track workouts with HealthKit on iOS and iPadOS
App Services 进阶 0m

在 iOS 和 iPadOS 上用 HealthKit 追踪锻炼

Track workouts with HealthKit on iOS and iPadOS

2025年6月9日

在 Apple 官方观看视频

一句话判断

HealthKit 的 Workout API 终于完整支持 iPhone 和 iPad 了——和 Apple Watch 几乎一样的代码,加上锁屏 Live Activity 和 Siri 控制,甚至还有 crash recovery。

这场 Session 讲了什么

如果你之前只在 Apple Watch 上做锻炼追踪,现在可以把同样的代码搬到 iPhone/iPad 上了。核心流程完全一致:

  1. 创建 HKWorkoutConfiguration(类型 + 位置)
  2. 创建 HKWorkoutSession,获取 builder,设置 data source
  3. prepare() 后 3 秒倒计时,让传感器就绪
  4. startActivity() + beginCollection()
  5. 通过 builder delegate 获取实时指标
  6. stopActivity() -> endCollection() -> finishWorkout() -> end()

和 Watch 的关键区别

  1. 传感器差异:iPhone/iPad 没有心率传感器,需要配对 BLE 心率带(如 Powerbeats Pro 2)。系统会自动处理心率数据。
  2. Generated vs Collected types:Generated types 是系统在锻炼期间自动产生的(卡路里、距离);Collected types 是你想观察并添加到锻炼样本的数据(比如锻炼期间喝的水)。可以用 enableCollection(for:) / disableCollection(for:) 控制。
  3. 锁屏行为:iPhone 很可能在锻炼时锁屏。首次启动锻炼时系统会提示”即使锁屏也可访问锻炼数据”。你的 app 应该用 Live Activity 在锁屏显示关键指标。
  4. Siri 锁屏控制:新增 Siri Intent 支持在锁屏上启动、暂停、恢复、取消锻炼,不需要解锁。
  5. Crash Recovery:系统自动重启崩溃的 app,恢复 workout session 和 builder 状态,但你需要重建 data source。新增 scene delegate 处理恢复流程。

值得深挖的点

  1. Builder delegate 是更新 UI 的正确方式。不需要 anchored object query,delegate 会在新数据到达时自动回调,而且自动处理 workout 保存时的指标同步。

  2. 锁屏隐私提示的 UX 影响。用户可以选择拒绝锁屏数据访问。如果你的 app 依赖心率,但设备锁屏且用户拒绝了访问,你应该优雅降级(比如只显示锻炼时长)。

  3. Siri Intent 必须在 app 内处理,不能在 extension 里。这意味着锁屏 Siri 命令会唤醒你的主 app。

  4. Crash Recovery 只需要重建 data source。Session 和 builder 状态由系统恢复,你只需要在 scene delegate 里重新关联 data source。

代码片段

完整的 workout session 生命周期:

let configuration = HKWorkoutConfiguration()
configuration.activityType = .running
configuration.locationType = .outdoor

let session = try HKWorkoutSession(healthStore: healthStore, configuration: configuration)
let builder = session.associatedWorkoutBuilder()

// 设置 data source
let device = HKDevice.local()
let dataSource = HKLiveWorkoutDataSource(healthStore: healthStore, workoutConfiguration: configuration)
builder.dataSource = dataSource

// 准备 + 开始
session.prepare()
// 3 秒倒计时...
session.startActivity()
try await builder.beginCollection(at: .now)

// 锁屏 Siri Intent 处理
class WorkoutIntentHandler: NSObject, StartWorkoutIntentHandling {
    func handle(intent: StartWorkoutIntent) async -> StartWorkoutIntentResponse {
        if workoutManager.isActive {
            return .failure(failureReason: "已有锻炼在进行")
        }
        let config = HKWorkoutConfiguration()
        config.activityType = .running
        config.locationType = .outdoor
        workoutManager.startWorkout(configuration: config)
        return .success()
    }
}

Crash Recovery:

func application(_ application: UIApplication,
                 shouldRestoreSecureApplicationState coder: NSCoder) -> Bool {
    return coder.decodeBool(forKey: "shouldHandleActiveWorkoutRecovery")
}

// Scene delegate 中恢复
let recoveredSession = try await healthStore.recoveredWorkoutSession()
workoutManager.recoverSession(recoveredSession)
// 只需重建 dataSource

最佳实践

  • 优先从 Watch 启动锻炼(如果用户有 Watch),用 healthStore.startWatchApp() 启动,然后 mirror 到 iPhone。这样能获取心率等全部指标。
  • 只请求你需要的数据类型授权。不要请求和锻炼无关的 HealthKit 权限。
  • 始终用 Workout Builder API 创建和保存 workout。这是确保 Activity Rings 正确更新的唯一方式。
  • 锻炼期间用 Live Activity 在锁屏显示关键指标。用 ActivityKit 配合 builder delegate 的实时数据。
  • 处理锁屏隐私场景。检查是否有数据访问权限,没有则优雅降级 UI。
  • Siri Intent handler 要处理”已有锻炼在进行”的情况,返回有意义的错误。

还有什么值得关注

  • WWDC23 的 “Build a multi-device workout app” 讲了 Watch + iPhone 的 mirror 机制。
  • WWDC24 的 “Bring your app’s core features to users with App Intents” 补充了 Siri Intent 的完整实现。
  • WWDC23 的 “Meet ActivityKit” 是 Live Activity 的基础。
  • HKQuantitySample 可能有 count > 1 的情况(更细粒度的数据),用 HKQuantitySeriesSampleQuery 读取。
  • Session 附带完整的 demo app,可以直接下载参考。
应用服务 Health & Fitness