← 所有文章

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 运行时契约,描述哪些会话类型可让应用在落腕期间继续运行。 

相关文章

HealthKit + SwiftUI on iOS 26: Authorization, Sample Types, and Cross-Platform Patterns

Real production patterns from Water (water tracking, HKQuantitySample) and Return (mindful sessions, HKCategorySample). …

17 分钟阅读

watchOS Runtime Is a Contract, Not a Background Task

watchOS does not have iOS's background. WKExtendedRuntimeSession is a contract you sign with the system, broken on wrist…

15 分钟阅读

The Cleanup Layer Is the Real AI Agent Market

Charlie Labs pivoted from building agents to cleaning up after them. The AI agent market is moving from generation to pr…

15 分钟阅读