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生命周期:notStarted→prepared→running→ (可选paused→running) →stopped→ended。状态转换通过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转到.running。Date参数让应用设置正式开始时间(通常是.now)。pause()。从.running转到.paused。resume()。从.paused转回.running。stopActivity(with: Date)。从.running(或.paused)转到.stopped。Date是正式结束时间。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+ 应用意味着什么
三点要义。
-
将生命周期与 UI 状态显式映射。 workout 应用的 UI 有显而易见的状态:未开始、准备中、活跃、暂停、汇总、完成。把每一个状态映射到
HKWorkoutSessionState。不要用临时布尔值驱动 UI;通过代理把它绑定到会话上报的状态。 -
任何要展示指标的会话都使用
prepare()加倒计时 UI。 3 秒预热是用户信任数据与不信任数据之间的差别。代价是一个小 UI 元素;收益是可靠的指标。 -
iOS 26 的 iPhone workout 会话需要不同的构建器代码。 会话API是共享的;构建器侧因平台而异。iOS 与 watchOS 之间共享代码路径的应用,需要显式的
#if os(watchOS)分支,或者使用一个抽象差异的封装层。
完整的 Apple 生态系列:类型化的App Intents;MCP服务器;路由问题;Foundation Models;运行时与工具LLM之分;三个界面;单一可信来源模式;两个MCP服务器;Apple 开发的钩子;Live Activities;watchOS 运行时;SwiftUI 内部;RealityKit 的空间心智模型;SwiftData 模式纪律;Liquid Glass 模式;多平台发布;平台矩阵;Vision 框架;Symbol Effects;Core ML 推理;Writing Tools API;Swift Testing;隐私清单;作为平台的无障碍;SF Pro 字体排印;visionOS 空间模式;Speech 框架;SwiftData 迁移;tvOS 焦点引擎;@Observable 内部;SwiftUI Layout 协议;自定义 SF Symbols;AVFoundation 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
-
Apple Developer Documentation:
HKWorkoutSession. 包含状态转换、配置和代理协议的会话类。 ↩↩ -
Apple Developer Documentation:
HKWorkoutSessionState. 五个状态枚举(.notStarted、.prepared、.running、.paused、.stopped、.ended)及其语义。 ↩↩ -
Apple Developer Documentation:
HKLiveWorkoutBuilder与HKLiveWorkoutDataSource。实时构建器API(watchOS 5+、iOS 26+、iPadOS 26+、Mac Catalyst 26+)及其数据源。 ↩↩ -
Apple Developer: Track workouts with HealthKit on iOS and iPadOS(WWDC 2025 session 322)。iOS 26 将
HKWorkoutSession扩展到 iPhone。 ↩ -
Apple Developer Documentation:
HKWorkoutSessionDelegate. 包含状态转换与错误回调的代理协议。 ↩ -
Apple Developer Documentation: Background Execution on watchOS. watchOS 运行时契约,描述哪些会话类型可让应用在落腕期间继续运行。 ↩