← 所有文章

HealthKit 健身鍛鍊生命週期:HKWorkoutSession 狀態與 iOS 26 跨平台介面

HKWorkoutSession 是 HealthKit 的健身鍛鍊狀態機。此工作階段歷經六個狀態(.notStarted.prepared.running.paused.stopped.ended),透過 HKWorkoutSessionDelegate 揭露生命週期事件,並(自 iOS 26 起)除了 Apple Watch 之外也能在 iPhone 上執行1。與工作階段搭配的 HKLiveWorkoutBuilder 會逐步收集樣本與事件;iOS 26 將相同的建構器 API 帶到了 iPhone。本系列的 watchOS 執行時期契約一文主張 watchOS 應用程式需要被系統識別的工作階段類型才能在背景中持續執行;HKWorkoutSession 正是其中一種工作階段類型,而其生命週期狀態直接對應到執行時期模型。

本文依照 Apple 官方文件來逐步說明健身鍛鍊的生命週期。整體框架是「每個狀態允許做什麼,以及每次轉換會觸發什麼」,因為健身鍛鍊應用程式如果未妥善管理生命週期,不是會遺失資料(過早離開 running 狀態),就是會耗盡電量(始終未離開 running 狀態)。

TL;DR

  • HKWorkoutSession 生命週期:notStartedpreparedrunning →(可選的 pausedrunning)→ stoppedended。狀態轉換透過 HKWorkoutSessionDelegate.workoutSession(_:didChangeTo:from:date:) 回報2
  • HKLiveWorkoutBuilder 是與健身鍛鍊工作階段搭配的即時資料累積器。它於 2018 年起源自 watchOS,並在 iOS 26+、iPadOS 26+ 與 Mac Catalyst 26+ 上推出。iPhone 健身鍛鍊使用與 Apple Watch 相同的 HKLiveWorkoutBuilder API,而執行時期模型與感測器可用性則因平台而異3
  • 工作階段上的 prepare() 方法會在 startActivity(_:) 開始實際健身鍛鍊之前先暖機感測器。Apple 建議在 prepare()startActivity(_:) 之間提供 3 秒倒數計時的 UI,讓心率感測器與外部藍牙裝置有時間連線。
  • stopped 狀態為過渡狀態:應用程式可在此狀態下完成指標彙整,但無法恢復工作階段。呼叫 end() 會轉換到 ended,這是終結狀態。
  • 本系列的 watchOS 執行時期契約一文涵蓋了健身鍛鍊工作階段如何讓 watchOS 應用程式在使用者放下手腕時仍持續執行。生命週期狀態機與執行時期保活契約是同一個介面的兩個面向。

六個狀態

HKWorkoutSessionState 列舉了整個生命週期2

.notStarted 工作階段已建立但尚未準備就緒。感測器尚未暖機;應用程式尚未被視為作用中的健身鍛鍊主機。當應用程式呼叫 prepare() 時,便會轉換到 .prepared

.prepared 工作階段已呼叫 prepare();感測器正在暖機,但健身鍛鍊尚未開始。心率監測器連線中、運動感測器初始化中、GPS 正在定位。面向使用者的常見模式是 3 秒倒數計時(「準備……3、2、1,開始!」);在此期間,系統有時間取得乾淨訊號,讓 running 狀態下最初的指標數據準確可靠。

.running 作用中的健身鍛鍊狀態。應用程式正在收集指標、顯示即時資料,並(在 watchOS 上)透過健身鍛鍊作用中執行時期契約讓螢幕保持開啟。透過 startActivity(_:) 進入 .running

.paused 由使用者暫停的狀態。應用程式不再收集作用中指標(例如距離),但工作階段被保留下來;呼叫 resume() 會回到 .running。在單一工作階段中,暫停/恢復循環可發生任意次數。

.stopped 健身鍛鍊結束後的過渡狀態。工作階段已結束作用階段但尚未完結;即時建構器仍可完成指標彙整。從 .stopped 呼叫 end() 會轉換到 .ended。應用程式無法從 .stopped 恢復。

.ended 終結狀態。工作階段已完成;即時建構器已被告知要完結;健身鍛鍊已儲存到 HealthKit(如果應用程式對建構器呼叫了 finishWorkout(completion:))。一旦進入 .ended,工作階段便無法再操作。

狀態圖中有一個必須注意的特定陷阱:從 .stopped 沒有路徑可回到 .running。如果使用者想「取消結束」健身鍛鍊,必須開啟新的工作階段,而不是恢復舊的。

驅動狀態轉換的方法

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()

三個元件將健身鍛鍊串連在一起:

  • HKWorkoutConfiguration 指定活動類型與位置。活動類型驅動指標的選擇(跑步健身鍛鍊會收集配速,室內單車則不會)。
  • HKLiveWorkoutDataSource 是工作階段感測器設定與建構器資料累積之間的橋樑。資料來源發布樣本;建構器接收並儲存樣本。
  • HKLiveWorkoutBuilder 持有進行中健身鍛鍊的狀態,並完結最終儲存的 HKWorkout 物件。

整個模式是逐步累積的:在 .running 狀態期間,樣本持續流入;建構器將其整合至執行中的統計資料;最後的 finishWorkout() 將完整的健身鍛鍊寫入 HealthKit。

iOS 26:在 iPhone 上進行健身鍛鍊

iOS 26 將 HKWorkoutSession 帶到了 iPhone,並使用與 watchOS 相同的 HKLiveWorkoutBuilder 與資料來源 API4。建構方式相同;平台間的差異在於執行時期模型、感測器可用性與隱私處理,而不在於 API 介面本身。

iOS 26 健身鍛鍊 API 帶來的應用情境: - 手機作為配套裝置的健身鍛鍊應用程式(iPhone 與 Watch 工作階段一同保存心率監測器資料)。 - 僅限 iPhone 的健身應用程式,供未持有 Apple Watch 的使用者使用,由 iPhone 透過內建感測器與已連線的配件追蹤工作階段。 - 跨裝置工作階段延續:Apple Watch 工作階段交接給 iPhone(使用者取下 Watch 但希望 iPhone 繼續追蹤),或反之亦然。

值得指出的平台差異: - 感測器可用性。 iPhone 有加速度計與 GPS,但沒有內建的心率感測器。在 iOS 健身鍛鍊上需要心率資料的應用程式,可搭配藍牙心率帶,或透過 HealthKit 從已連線的 Apple Watch 讀取。 - 執行時期模型。 Apple Watch 的健身鍛鍊作用中執行時期保證在使用者放下手腕期間仍可持續存取感測器。iPhone 的執行時期則仰賴系統一般的前景/背景生命週期,加上透過場景委派(已於 WWDC 2025 第 322 場議程中說明)的當機復原機制,這是另一種形式的保證。 - 隱私與鎖定畫面行為。 iPhone 在裝置鎖定時執行的健身鍛鍊,需要明確設定才能繼續收集樣本,因為鎖定畫面是比放下手腕更嚴格的隱私邊界。

委派協定

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(),所以我們現在正在執行」),會錯過系統套用的狀態變更(使用者靜止時的自動暫停、手錶被取下時的自動結束)。委派驅動的模式才是正確做法。

執行時期契約

HKWorkoutSession 是 watchOS 認可可讓應用程式在背景中持續執行的工作階段類型之一,與正念、鬧鐘及音訊錄製工作階段並列6。契約內容是:當工作階段處於 .prepared.running.paused.stopped 狀態時,應用程式會持續執行;使用者抬起手腕時螢幕會喚醒;感測器資料會持續串流至應用程式。

本系列的 watchOS 執行時期契約一文對此有詳盡說明。對健身鍛鍊應用程式而言的重點:生命週期狀態機正是告訴 watchOS「讓此應用程式持續執行」的機制;轉換到 .ended 會釋放契約,讓作業系統得以暫停應用程式。

實務上的意涵:不要過早結束健身鍛鍊工作階段。如果使用者離開健身鍛鍊去接電話後又回來,工作階段應留在 .running(或透過 pause() 暫停),而不是被結束。先結束再重新開始,會遺失資料與執行時期的延續性。

常見失敗模式

健身鍛鍊應用程式失敗紀錄中常見的三種模式:

跳過 prepare() 應用程式如果未先呼叫 prepare() 就直接呼叫 startActivity(_:),所產生的健身鍛鍊在最初 5 至 10 秒內的心率資料會不可靠(感測器尚未暖機)或缺失(藍牙心率帶尚未連線)。修正方式:一律先呼叫 prepare(),顯示簡短的倒數計時 UI,再呼叫 startActivity(_:)

直接從 .running 呼叫 end() 跳過 .stopped 等於跳過指標完結視窗。即時建構器可能在工作階段終結之前還沒處理完最後的樣本,導致摘要統計遺失。修正方式:一律先呼叫 stopActivity(_:),等待委派回呼確認進入 .stopped,再呼叫 end()

推論狀態而不使用委派。 應用程式如果只追蹤本機狀態(isWorkoutActive: Bool)而從未串接委派,就會錯過由系統驅動的狀態轉換(自動暫停、手錶取下時自動結束、錯誤狀態)。修正方式:一律以委派作為可信來源。

此模式對 iOS 26+ 應用程式的意義

三點要點。

  1. 將生命週期明確對應到 UI 狀態。 健身鍛鍊應用程式的 UI 有顯而易見的狀態:未開始、準備中、進行中、已暫停、摘要、完成。將每一個狀態對應到 HKWorkoutSessionState。不要用零散的布林值驅動 UI;應透過委派將 UI 綁定到工作階段所回報的狀態。

  2. 任何揭露指標的工作階段都應使用 prepare() 加倒數計時 UI。 3 秒暖機是「使用者信任的資料」與「使用者打折扣的資料」之間的差別。代價是一個小小的 UI 元素;換得的是可靠的指標。

  3. iOS 26 的 iPhone 健身鍛鍊工作階段需要不同的建構器程式碼。 工作階段 API 是共用的;建構器這一側則因平台而異。應用程式如果在 iOS 與 watchOS 之間共用同一條程式碼路徑,需要明確的 #if os(watchOS) 分支,或是包裝層來抽象化此差異。

完整的 Apple 生態系列:型別化的 App IntentsMCP 伺服器路由抉擇Foundation Models執行時期與工具 LLM 之分三種介面單一可信來源模式兩個 MCP 伺服器Apple 開發中的 hooksLive 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 代理」相關脈絡,請參閱 iOS Agent 開發指南

常見問答

iPhone 使用的是與 Apple Watch 相同的 HKLiveWorkoutBuilder 嗎?

是的,自 iOS 26 起便是如此。相同的 HKLiveWorkoutBuilder API 同時在 iOS 26+、iPadOS 26+、Mac Catalyst 26+ 與 watchOS 5+ 上推出。平台差異在於執行時期模型與感測器可用性,而不在於建構器 API 本身。iPhone 健身鍛鍊透過場景委派處理鎖定畫面隱私與當機復原(依 WWDC 2025 第 322 場議程所述),這與 watchOS 的放下手腕執行時期保證有所不同,但資料累積的 API 是相同的。

健身鍛鍊的最長時長是多少?

並沒有硬性的時長上限。實務上的限制來自電量(Apple Watch 在持續健身鍛鍊下約可撐 6 至 8 小時)與儲存空間(高頻率資料的健身鍛鍊累積得很快)。馬拉松應用程式(12 小時以上的健身鍛鍊)已能順利出貨;框架本身完全支援。

我該如何處理自動暫停?

HKWorkoutConfiguration.activityType 設為支援自動暫停的類型(例如 .running)。watchOS 會根據使用者的動作自動暫停與恢復。狀態轉換會透過委派傳遞;以與使用者主動暫停相同的方式處理即可。

如果使用者在健身鍛鍊途中取下手錶會發生什麼事?

工作階段會繼續維持目前的狀態(通常是 .running)。如果手錶離開手腕的時間過久,watchOS 系統最終會結束工作階段;此時委派的 didFailWithError 回呼會觸發。具備跨裝置工作階段(iOS 26+)的應用程式,若使用者同時持有兩種裝置,便可交接給 iPhone。

我應該將健身鍛鍊儲存到 HealthKit 嗎?

幾乎一律應該。呼叫 builder.finishWorkout(completion:) 會將完整的健身鍛鍊寫入 HealthKit,這表示資料會出現在「體能訓練」應用程式、「健康」應用程式的健身鍛鍊清單,以及使用者已授權的其他任何應用程式中。略過儲存便等於丟棄資料;框架並不提供任何回復管道。

這與近期 Apple Health 的其他新增功能有何關聯?

iOS 26 / watchOS 26 在兩個具體面向上擴展了健身鍛鍊 API:第一,將 HKWorkoutSession 帶到 iPhone(前文已涵蓋);第二,擴大了活動類型清單與自動偵測涵蓋範圍。本系列的 watchOS 執行時期契約一文涵蓋執行時期面向;本文涵蓋生命週期面向。兩者合在一起,便描繪出推出健身鍛鍊應用程式所需的完整介面。

參考資料


  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 第 322 場議程)。將 HKWorkoutSession 擴展至 iPhone 的 iOS 26 變革。 

  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 分鐘閱讀