← 所有文章

HealthKit Workout 生命周期:HKWorkoutSession 状态与 iOS 26 跨平台界面

HKWorkoutSession是 HealthKit 的 workout 状态机。会话经历六个状态(.notStarted.prepared.running.paused.stopped.ended),通过HKWorkoutSessionDelegate暴露生命周期事件,并且(自 iOS 26 起)除 Apple Watch 外也能在 iPhone 上运行1。与会话配对的HKLiveWorkoutBuilder以增量方式收集样本和事件;iOS 26 将同一构建器API引入了 iPhone。本系列的watchOS 运行时契约一文论证过:watchOS 应用需要一种被系统识别的会话类型才能在后台持续运行;HKWorkoutSession正是这样的会话类型之一,其生命周期状态直接映射到运行时模型。

本文将对照 Apple 官方文档梳理 workout 生命周期。叙述框架是”每个状态允许什么、每个转换触发什么”,因为生命周期管理失误的 workout 应用要么丢数据(过早脱离 running 状态),要么耗电(始终不脱离 running 状态)。

TL;DR

  • HKWorkoutSession生命周期:notStartedpreparedrunning → (可选pausedrunning) → stoppedended。状态转换通过HKWorkoutSessionDelegate.workoutSession(_:didChangeTo:from:date:)上报2
  • HKLiveWorkoutBuilder是与 workout 会话配对的实时数据累积器。它最初于 2018 年登陆 watchOS,并在 iOS 26+、iPadOS 26+ 和 Mac Catalyst 26+ 上发布。iPhone workout 使用与 Apple Watch 相同的HKLiveWorkoutBuilderAPI,仅在运行时模型与传感器可用性方面存在平台差异3
  • 会话上的prepare()方法会在startActivity(_:)真正启动 workout 之前预热传感器。Apple 建议在prepare()startActivity(_:)之间加入 3 秒倒计时 UI,让心率传感器和外接蓝牙设备有时间完成连接。
  • stopped状态是过渡态:应用可在此状态下完成指标收尾,但无法恢复会话。调用end()会进入ended状态,这是终态。
  • 本系列的watchOS 运行时契约一文介绍了 workout 会话如何让 watchOS 应用在落腕期间继续运行。生命周期状态机与运行时保活契约是同一个界面的一体两面。

六个状态

HKWorkoutSessionState枚举了整个生命周期2

.notStarted 会话已创建但尚未准备。传感器尚未预热;应用尚未被视为活跃的 workout 宿主。当应用调用prepare()时,进入.prepared

.prepared 会话已调用prepare();传感器正在预热,但 workout 尚未开始。心率监测仪开始连接、运动传感器初始化、GPS 完成定位。面向用户的常见模式是 3 秒倒计时(”准备好… 3、2、1,开始!”);在这段窗口里,系统有时间获取干净信号,使 running 状态下的首批指标准确可靠。

.running 活跃的 workout 状态。应用正在采集指标、显示实时数据,并(在 watchOS 上)通过 workout-active 运行时契约保持屏幕常亮。通过startActivity(_:)进入.running

.paused 用户暂停状态。应用不再采集活跃指标(如距离),但会话被保留;调用resume()返回.running。暂停/恢复循环可在单个会话内任意次数发生。

.stopped workout 结束后的过渡态。会话已结束活跃阶段但尚未最终化;实时构建器仍可完成指标收尾。从.stopped调用end()进入.ended。应用无法从.stopped恢复。

.ended 终态。会话结束;实时构建器已被告知最终化;workout 已保存到 HealthKit(前提是应用调用了构建器上的finishWorkout(completion:))。一旦进入.ended,会话便不再可操作。

状态图有一个具体陷阱:从.stopped没有任何路径回到.running。如果用户想”取消结束”workout,必须开启新会话,而不能恢复旧会话。

驱动状态转换的方法

HKWorkoutSession暴露以下方法用于状态转换1

  • prepare()。从.notStarted转到.prepared。预热传感器。
  • startActivity(with: Date)。从.prepared转到.runningDate参数让应用设置正式开始时间(通常是.now)。
  • pause()。从.running转到.paused
  • resume()。从.paused转回.running
  • stopActivity(with: Date)。从.running(或.paused)转到.stoppedDate是正式结束时间。
  • end()。从.stopped转到.ended

prepare()startActivity(_:)之间是预热窗口。stopActivity(_:)end()之间是收尾窗口:实时构建器有机会在会话终止前补充最后的样本。

watchOS 与 iPhone 上的HKLiveWorkoutBuilder

HKLiveWorkoutBuilder是与会话配对的实时数据累积器3。该构建器随 watchOS 5 在 watchOS 上发布,并扩展到 iOS 26+、iPadOS 26+ 和 Mac Catalyst 26+。构建器的生命周期与会话的生命周期配对:

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

let session = try HKWorkoutSession(healthStore: store, configuration: configuration)
let builder = session.associatedWorkoutBuilder()
builder.dataSource = HKLiveWorkoutDataSource(healthStore: store, workoutConfiguration: configuration)

session.delegate = self
builder.delegate = self

session.prepare()
// User taps Start after countdown
session.startActivity(with: Date())
try await builder.beginCollection(at: Date())

// During the workout, metrics flow into the builder via the data source.
// builder.collectedTypes contains the sample types being collected.
// builder.statistics(for:) returns running stats.

// User ends the workout
session.stopActivity(with: Date())
try await builder.endCollection(at: Date())
let workout = try await builder.finishWorkout()
session.end()

三个组件把 workout 黏合在一起:

  • HKWorkoutConfiguration指定活动类型和地点。活动类型决定指标选择(跑步 workout 采集配速,室内骑行不采集)。
  • HKLiveWorkoutDataSource是从会话传感器配置到构建器数据累积的桥梁。数据源发布样本;构建器接收并存储。
  • HKLiveWorkoutBuilder保存进行中 workout 的状态,并最终化保存的HKWorkout对象。

模式是增量式的:样本在.running状态下持续流入;构建器将其整合为运行统计;最终的finishWorkout()将完整 workout 写入 HealthKit。

iOS 26:iPhone 上的 workout

iOS 26 将HKWorkoutSession引入 iPhone,并使用与 watchOS 相同的HKLiveWorkoutBuilder和数据源API4。构造方式相同;平台差异体现在运行时模型、传感器可用性和隐私处理上,而不在API层面。

iOS 26 的 workout API支持的使用场景: - 手机作为伴侣的 workout 应用(iPhone 与 Watch 会话并行保存心率监测仪数据)。 - 仅 iPhone 的健身应用,面向没有 Apple Watch 的用户,由 iPhone 通过内置传感器和外接配件追踪会话。 - 跨设备会话延续:Apple Watch 会话交接给 iPhone(用户摘下 Watch 但希望 iPhone 继续追踪),或反向交接。

值得点名的平台差异: - 传感器可用性。 iPhone 配备加速度计和 GPS,但没有内置心率传感器。iOS workout 中需要心率的应用,需配对蓝牙心率带,或通过 HealthKit 从已连接的 Apple Watch 读取。 - 运行时模型。 Apple Watch 的 workout-active 运行时在落腕期间保证传感器持续可用。iPhone 的运行时依赖系统正常的前台/后台生命周期,再加上通过场景代理实现的崩溃恢复(详见 WWDC 2025 session 322),这是另一种形态的保证。 - 隐私与锁屏行为。 iPhone workout 在设备锁定时仍要继续采集样本,需要显式配置,因为锁屏比落腕是更强的隐私边界。

代理协议

HKWorkoutSessionDelegate上报状态转换和错误5

extension WorkoutCoordinator: HKWorkoutSessionDelegate {
    func workoutSession(
        _ workoutSession: HKWorkoutSession,
        didChangeTo toState: HKWorkoutSessionState,
        from fromState: HKWorkoutSessionState,
        date: Date
    ) {
        switch toState {
        case .running:
            // workout is active
        case .paused:
            // user paused
        case .stopped:
            // finalize metrics
        case .ended:
            // workout done; cleanup
        default:
            break
        }
    }

    func workoutSession(
        _ workoutSession: HKWorkoutSession,
        didFailWithError error: Error
    ) {
        // session failed (e.g., heart rate sensor disconnected unexpectedly)
    }
}

代理是状态转换的唯一可信来源。从方法调用推断状态的应用(”我调用了startActivity(),所以现在是 running”)会错过系统自动应用的状态变化(用户静止时自动暂停、Watch 被摘下时自动结束)。代理驱动的模式才是正解。

运行时契约

HKWorkoutSession是 watchOS 识别的、可让应用在后台保持运行的会话类型之一,与正念、闹钟、音频录制会话并列6。契约是:当会话处于.prepared.running.paused.stopped状态时,应用持续运行;用户抬腕时屏幕亮起;传感器持续向应用推送数据。

本系列的watchOS 运行时契约一文有更详尽的论述。对 workout 应用而言,关键点是:生命周期状态机正是告诉 watchOS”让这个应用继续运行”的依据;进入.ended即释放契约,系统可以挂起应用。

一个实践推论:不要过早结束 workout 会话。如果用户因接电话暂时离开后又回来,会话应保留在.running(或通过pause()暂停),而不应被结束。结束后再重启会丢失数据,也会中断运行时连续性。

常见失败

来自 workout 应用故障日志的三种模式:

跳过prepare() 不先调用prepare()就调用startActivity(_:)的应用,产出的 workout 中前 5–10 秒的心率数据要么不可靠(传感器未预热),要么缺失(蓝牙心率带尚未连接)。修复办法:始终调用prepare(),展示简短倒计时 UI,再startActivity(_:)

直接从.running调用end() 跳过.stopped等于跳过指标最终化窗口。实时构建器可能在会话终止前还来不及处理最后的样本,导致汇总统计缺失。修复办法:始终先调用stopActivity(_:),等待代理回调确认进入.stopped,再调用end()

用推断代替代理。 仅追踪本地状态(isWorkoutActive: Bool)而从不挂代理的应用,会错过系统驱动的状态转换(自动暂停、摘表自动结束、错误状态)。修复办法:始终以代理为可信来源。

这一模式对 iOS 26+ 应用意味着什么

三点要义。

  1. 将生命周期与 UI 状态显式映射。 workout 应用的 UI 有显而易见的状态:未开始、准备中、活跃、暂停、汇总、完成。把每一个状态映射到HKWorkoutSessionState。不要用临时布尔值驱动 UI;通过代理把它绑定到会话上报的状态。

  2. 任何要展示指标的会话都使用prepare()加倒计时 UI。 3 秒预热是用户信任数据与不信任数据之间的差别。代价是一个小 UI 元素;收益是可靠的指标。

  3. iOS 26 的 iPhone workout 会话需要不同的构建器代码。 会话API是共享的;构建器侧因平台而异。iOS 与 watchOS 之间共享代码路径的应用,需要显式的#if os(watchOS)分支,或者使用一个抽象差异的封装层。

完整的 Apple 生态系列:类型化的App IntentsMCP服务器路由问题Foundation Models运行时与工具LLM之分三个界面单一可信来源模式两个MCP服务器Apple 开发的钩子Live ActivitieswatchOS 运行时SwiftUI 内部RealityKit 的空间心智模型SwiftData 模式纪律Liquid Glass 模式多平台发布平台矩阵Vision 框架Symbol EffectsCore ML 推理Writing Tools APISwift Testing隐私清单作为平台的无障碍SF Pro 字体排印visionOS 空间模式Speech 框架SwiftData 迁移tvOS 焦点引擎@Observable 内部SwiftUI Layout 协议自定义 SF SymbolsAVFoundation HDR我拒绝写的题目。系列首页位于Apple 生态系列。如需更广泛的 iOS 与 AI agent 结合上下文,请参阅iOS Agent 开发指南

FAQ

iPhone 是否使用与 Apple Watch 相同的HKLiveWorkoutBuilder

是的,自 iOS 26 起。同一套HKLiveWorkoutBuilderAPI发布在 iOS 26+、iPadOS 26+、Mac Catalyst 26+ 和 watchOS 5+ 上。平台差异体现在运行时模型与传感器可用性,而非构建器API本身。iPhone workout 通过场景代理处理锁屏隐私和崩溃恢复(依据 WWDC 2025 session 322),这与 watchOS 的落腕运行时保证不同,但数据累积API是相同的。

workout 时长上限是多少?

没有硬性时长上限。实际限制来自电池(Apple Watch 在持续 workout 下约能维持 6–8 小时)和存储(高频数据的 workout 体积增长很快)。马拉松跑步类应用(12 小时以上的 workout)今天即可正常发布;框架本身支持。

如何处理自动暂停?

HKWorkoutConfiguration.activityType设置为支持自动暂停的类型(如.running)。watchOS 会根据用户运动情况自动暂停和恢复。状态转换照样通过代理传递;处理方式与用户手动暂停一致。

如果用户在 workout 中途摘下 Watch 会怎样?

会话保持当前状态(通常是.running)。如果手表长时间脱离手腕,watchOS 系统最终会结束该会话;届时会触发代理的didFailWithError回调。具备跨设备会话能力的应用(iOS 26+)可在用户同时拥有两台设备时把会话交接给 iPhone。

我应该把 workout 保存到 HealthKit 吗?

几乎总是该保存。调用builder.finishWorkout(completion:)会把完整 workout 写入 HealthKit,意味着数据会出现在”体能训练”应用、”健康”应用的 workout 列表中,以及用户授权的其他任何应用里。跳过保存等于丢弃数据;框架不提供任何恢复路径。

这与 Apple Health 近期其他新增功能有何关系?

iOS 26 / watchOS 26 在两个具体方向扩展了 workout API:第一,把HKWorkoutSession引入 iPhone(如上所述);第二,扩大活动类型清单与自动检测覆盖范围。本系列的watchOS 运行时契约一文谈运行时侧;本文谈生命周期侧。两者合在一起,描绘出发布一个 workout 应用所需的完整界面。

References


  1. Apple Developer Documentation: HKWorkoutSession. 包含状态转换、配置和代理协议的会话类。 

  2. Apple Developer Documentation: HKWorkoutSessionState. 五个状态枚举(.notStarted.prepared.running.paused.stopped.ended)及其语义。 

  3. Apple Developer Documentation: HKLiveWorkoutBuilderHKLiveWorkoutDataSource。实时构建器API(watchOS 5+、iOS 26+、iPadOS 26+、Mac Catalyst 26+)及其数据源。 

  4. Apple Developer: Track workouts with HealthKit on iOS and iPadOS(WWDC 2025 session 322)。iOS 26 将HKWorkoutSession扩展到 iPhone。 

  5. Apple Developer Documentation: HKWorkoutSessionDelegate. 包含状态转换与错误回调的代理协议。 

  6. Apple Developer Documentation: Background Execution on watchOS. watchOS 运行时契约,描述哪些会话类型可让应用在落腕期间继续运行。 

相关文章

iOS 26 上的 HealthKit + SwiftUI:来自两款已上架应用的授权流程、样本类型与跨平台模式

来自 Water(饮水追踪,HKQuantitySample)和 Return(正念会话,HKCategorySample)的真实生产模式。权限 UX、async 封装、watchOS 变体,以及需要避开的陷阱。

5 分钟阅读

watchOS运行时是一种契约,而非后台任务

watchOS没有iOS式的后台。WKExtendedRuntimeSession就是契约;若不使用,应用会在落腕时挂起。Return已落地此模式。

2 分钟阅读

循环工程:在验证成本低廉处,循环才能取胜

循环工程,对照 Boris Cherny 的完整访谈记录来检验:他点名的每一个循环,验证成本都很低。正是这一约束决定了什么值得自动化。

4 分钟阅读