View in English

  • 打开菜单 关闭菜单
  • Apple Developer
搜索
关闭搜索
  • Apple Developer
  • 新闻
  • 探索
  • 设计
  • 开发
  • 分发
  • 支持
  • 账户
在“”范围内搜索。

快捷链接

5 快捷链接

视频

打开菜单 关闭菜单
  • 专题
  • 相关主题
  • 所有视频
  • 关于

更多视频

  • 简介
  • 概要
  • 转写文稿
  • 代码
  • 使用 iOS 和 iPadOS 上的 HealthKit 跟踪体能训练

    了解有关为 iOS 打造出色体能训练体验的最佳做法。探究体能训练会话的生命周期,探索 Apple Watch 上和 iPhone 上体能训练的不同之处,并了解如何使用实时活动和 Siri 来提升 App 的锁屏体验。

    章节

    • 0:00 - 简介
    • 0:56 - 启动体能训练会话
    • 2:50 - 获取体能训练指标
    • 8:35 - 崩溃恢复
    • 9:34 - 最佳实践

    资源

    • Building a multidevice workout app
    • Building a workout app for iPhone and iPad
    • Handling Workout Requests with SiriKit
    • HKWorkoutSession
    • Running workout sessions
      • 高清视频
      • 标清视频

    相关视频

    WWDC25

    • 了解 HealthKit Medications API

    WWDC24

    • 利用 App Intents 为用户奉上 App 的核心功能

    WWDC23

    • 了解 ActivityKit
    • 构建多设备训练 App
  • 搜索此视频…

    大家好 欢迎各位 我是 Brian HealthKit 团队的工程师 目前已有数百款健康健身 App 帮助人们获得并保持健康 在征得你的许可后 这些 App 可以访问 HealthKit 集中管理的加密数据库 以及一组功能强大的 API 为你提供完整的健康数据概览 现在 体能训练 API 是 HealthKit 提供的最强大的 API 之一 很高兴能向大家介绍如何 在 iPhone 和 iPad 上使用这些 API 接下来我将从 体能训练会话的基础知识讲起 然后重点解析如何在训练中 获取健康指标数据 特别是 iPhone/iPad 与 Apple Watch 操作流程的差异 随后会演示崩溃后的恢复方法 最后分享一些关于训练的 实用技巧和最佳实践 让我们开始这场体能训练会话之旅吧 如果你已在 Apple Watch 上的 App 中运行过体能训练功能 那么只需稍作调整 就能将同一套 代码移植到 iPhone 和 iPad 上使用 与 Apple Watch 端一样 你现在 可通过体能训练会话来追踪各类运动 并利用配套的体能训练构建器 将训练数据保存在 HealthKit 中 考虑到你可能尚未在 Apple Watch 上开发过 App 我将快速演示如何运行 一个体能训练会话 完整的体能训练会话流程包含多个 环节 从初始化配置、启动会话 到采集健康指标数据 最后结束会话 首先 你需要先创建一个 体能训练配置对象 并设置它的类型以匹配 用户将要进行的活动 这里我以户外跑步为例进行配置 接着 通过传入这个配置对象来 创建一个 HKWorkoutSession 实例

    从这个体能训练会话中 你可以获取关联的数据构建器 并绑定数据源

    然后调用会话的 prepare 方法 并显示 3 秒倒计时界面 这既为设备传感器的启动 留出缓冲时间 也便于外接心率监测器等设备 完成连接 这段倒计时能确保训练活动一开始 就能获取各项指标数据 倒计时结束后 你只需调用 会话的 startActivity 并在关联的训练构建器上 执行 beginCollection 即可 你无需使用锚定对象查询 来更新 UI 训练构建器的委托机制会在 收集到新数据时 主动通知 App 更新 并在保存训练记录时 自动保持所有指标数据的同步

    当用户在 App 上结束训练时 应调用会话的 stopActivity 这样实时构建器就能完成 最终指标数据的采集

    当会话进入停止状态后 即可调用构建器的 endCollection 并结束本次训练 构建器完成处理后 调用会话的 end 方法 同时展示训练总结界面

    好了 现在你已经了解 基本的训练运行流程 接下来我要重点讲解 在 Apple Watch 与 iPhone/iPad 上运行训练功能的主要差异 一个关键区别在于可用传感器

    虽然 iPhone 和 iPad 支持 所有类型的体能训练活动 但这些设备本身并不配备心率传感器

    但你可以将它们与任何 支持心率 GAT 协议的 训练用穿戴设备配对使用 例如外接心率监测器或 Powerbeats Pro 2 耳机

    设备配对成功后 HealthKit 将负责 从设备获取心率数据 并将它作为样本保存至健康数据库 供你的 App 调用 这意味着你希望为训练 收集的样本数据 与系统能够生成的样本数据 可能存在差异 下面我们来详细解析这一差异

    系统生成类型 指由系统在训练活动中 自动生成的数据类型 如卡路里和距离 主动收集类型 则是你需要 实时观测并添加到训练样本中的指标 例如 若你的 App 需要 收集训练期间的水分摄入量 则需主动将相关样本 添加至健康数据库

    在 iPhone 和 iPad 上初始化时 数据源中预设的待收集类型 将包含当前活动 可能需要的所有样本类型 例如 即便系统本身 无法生成心率数据 这个数据也会被包含在待收集类型中 除非连接了外部心率传感器

    数据源会持续监测所有样本和类型 收集由系统生成或 由 App 保存的数据 并将它们传递给实时构建器

    若需确认系统实际生成的数据类型 可以使用与更新 UI 指标相同的 Workout Builder 委托

    如果你的 App 要修改 默认收集的数据类型 可以对数据源上的类型方法 调用启用或禁用数据收集功能 从而添加或移除所需类型

    例如 若需收集训练期间的饮水量 App 将调用“启用数据收集” 在进行体能训练时 将测量值作为样本写入健康数据库 数据源会自动 将这些样本传递给实时构建器 现在你已掌握 在会话中获取指标的方法 我们稍作停顿 快速了解 如何读取已保存的训练数据

    首先通过训练对象的 统计信息显示摘要数据

    若需绘制整个训练过程中 指标的变化曲线 则应使用统计集合查询 并设置所需的时间间隔

    若你的 App 需要获取细粒度数据 请注意 与训练相关的数量样本 可能包含多个数据点 这表明存在更高精度的细分数据 此时应改用 HKQuantitySeriesSampleQuery 进行访问

    你可能已经注意到 查看 Apple Watch 历史训练数据时 会出现这种情况 iOS 系统中保存的训练数据 同样适用这一规则 很好 现在你已经知道如何 在 App 处于前台时收集指标数据 并在训练结束后读取这些数据 另一个关键区别是 与 Apple Watch 不同 iPhone 在运动过程中 很可能会锁定屏幕 出于隐私保护考虑 设备锁定时 通常无法访问健康数据 但无需担心 当首次开启体能训练会话时 系统会显示提示 表明即使设备锁定 你的 App 仍可获取运动数据 这为你的 App 提供了一个绝佳机会 可以在锁屏界面 通过实时活动展示关键运动指标 让用户无需解锁手机 就能直接查看实时数据更新 但还记得我刚才提到的隐私提示吗? 如果设备锁定时无法获取数据 或心率数据不可用 你可能需要调整 UI 设计 暂时隐藏具体指标 仅显示训练时长

    而锁屏操作的可能性远不止于此 我们很高兴现已支持 在锁屏时直接调用 Siri 现在 你无需解锁手机 即可开始、暂停、 恢复或取消体能训练 手机解锁后 HealthKit 会自动保存训练数据 并通过 Health Store 供你的 App 调用 下面我将介绍如何为你的 App 添加支持锁屏操作的 Siri 意图

    首先需要定义意图处理程序 这个程序必须内置于你的 App 中 才能实现锁屏操作 接着 你需要明确设定 希望支持的意图类型 我在示例中将它们单独列出 以便更清晰易读 接下来你需要处理传入的意图 这里我收到了 StartWorkoutIntent 你首先需要检查当前 是否有正在进行的训练 若存在 则返回失败响应 接着你需要获取活动类型和位置信息 在本示例中 我会直接将它设置为户外跑步 完成这些操作后 你将返回一个成功响应

    现在你已定义好意图 接下来需要创建一个 App 委托 来响应这些意图 你将在 App 中定义这个委托

    至此 你的 App 现已支持通过 锁屏界面调用 Siri 训练意图

    添加 Siri 意图 和实时活动功能将确保 用户无论设备是否处于锁屏状态 都能充分利用你的 App 如需详细了解这两种技术 请观看 WWDC24“利用 App Intents 为用户奉上 App 的核心功能” 及 WWDC23 的“了解 ActivityKit” 现在你已了解如何获取训练会话指标 以及如何在实时活动中 调用 Siri 意图 接下来讲讲崩溃恢复功能 这项功能在 Apple Watch 上已推出了一段时间 但我还是想谈谈三个关键点 系统会自动重启崩溃的 App 构建器中的体能训练会话 会恢复到之前的状态 但你需要重新配置实时数据源 对于 iPhone 和 iPad 我们新增了一个场景委托 专门用于恢复进行中的训练会话

    你可以使用之前为 Siri 意图 创建的 App 委托 来添加处理崩溃恢复的场景委托 接下来 我们先定义 App 委托 并检查 options 参数 是否包含 shouldHandleActiveWorkoutRecovery 确认需要恢复后 我们会从 Health Store 获取 恢复的 workoutSession 并确保将 recoveredSession 传递给 你的 WorkoutManager 最后 通过 WorkoutManager 可继续处理被中断的训练会话 如果你还记得 我们只需要 重新创建 dataSource 即可

    最后 我来总结一些 关于训练的最佳实践 如果你有 Watch App 务必在那里开启锻炼 以获得所有可用的指标数据 请直接从健康数据库 启动 Watch App 启动后 务必将训练数据 同步到 iPhone 上 具体操作方法请查看 WWDC23 的 “构建多设备训练 App”

    你的 App 仅请求 所需数据类型的授权 不要让用户困惑为何要获取 与 App 核心功能无关的 数据类型授权 最后 请始终使用 Workout Builder API 来创建和保存训练数据 这将确保健身记录圆环能正确更新

    这就是在 iPhone 和 iPad 上通过 HealthKit 追踪训练的方法 通过这次更新 这些设备现在拥有了 具备崩溃恢复能力的强大 API 即使在屏幕锁定时 也能显示和管理训练数据 在结束前 请完成以下准备步骤 请务必下载本讲座随附的演示 App 其中包含我今天分享的所有代码 它们构成了一个功能完整的示例 可供你直接用于开发起步 如果你已有 iPhone 或 iPad App 请务必升级到我今天介绍的 Workout Builder API 我相信这些改进一定会让你满意 如果你已有 Apple Watch App 那么同一 API 的多平台支持 意味着你的 App 将面向没有 Apple Watch 的用户开辟全新市场 最后要说明的是 我们实现的许多功能 都是你反馈的直接结果 请继续不吝赐教 我们的目标是通过技术支持 助你打造更多卓越的 App 推动全球健康事业的发展 感谢你的观看

    • 1:30 - Set up workout session

      // Set up workout session
      
      // Create workout configuration
      let configuration = HKWorkoutConfiguration()
      configuration.activityType = .running
      configuration.locationType = .outdoor
      
      // Create workout session
      let session = try HKWorkoutSession(healthStore: healthStore, configuration: configuration)
      session.delegate = self
      
      // Get associated workout builder and add data source
      let builder = session.associatedWorkoutBuilder()
      builder.delegate = self
      builder.dataSource = HKLiveWorkoutDataSource(healthStore: healthStore,
                                                   workoutConfiguration: configuration)
    • 1:54 - Starting the session

      // Prepare and start session
      
      session.prepare()
      
      // Start and display count down
      
      // Start session and builder collection once count down finishes
      session.startActivity(with: startDate)
      try await builder.beginCollection(at: startDate)
    • 2:14 - Handling Metrics

      // Handling collected metrics
      
      func workoutBuilder(_ workoutBuilder: HKLiveWorkoutBuilder, 
                          didCollectDataOf collectedTypes: Set<HKSampleType>) {
          for type in collectedTypes {
              guard let quantityType = type as? HKQuantityType else { return }
      
              let statistics = workoutBuilder.statistics(for: quantityType)
      
              // Update the published values
              updateForStatistics(statistics)
          }
      }
    • 2:28 - Ending workout

      // Stopping the workout session
      
      session.stopActivity(with: .now)
      
      // Session transitions to stopped then call end
      func workoutSession(_ workoutSession: HKWorkoutSession,
                          didChangeTo toState: HKWorkoutSessionState,
                          from fromState: HKWorkoutSessionState,
                          date: Date) {
          guard change.newState == .stopped, let builder else { return }
           
          try await builder.endCollection(at: change.date)
          let finishedWorkout = try await builder.finishWorkout()
          session.end()
      }
    • 7:17 - Set up Siri Intent

      // Create an INExtension within your main app
      
      // Define an intent handler
      public class IntentHandler: INExtension {
      
      }
      
      // Define the intents to support
      extension IntentHandler: INStartWorkoutIntentHandling
      
      extension IntentHandler: INPauseWorkoutIntentHandling
      
      extension IntentHandler: INResumeWorkoutIntentHandling
      
      extension IntentHandler: INEndWorkoutIntentHandling
    • 7:32 - Handle the Siri intent

      // Handle the intent
      
      public func handle(intent: INStartWorkoutIntent) async -> INStartWorkoutIntentResponse {
          let state = await WorkoutManager.shared.state
              
          switch state {
          case .running, .paused, .prepared, .stopped:
              return INStartWorkoutIntentResponse(code: .failureOngoingWorkout, 
                                                  userActivity: nil)
          default:
              break;
          }
          Task {
              await MainActor.run {
                  // Handle the intents activity type and location
                  WorkoutManager.shared.setWorkoutConfiguration(activityType: .running,   
                                                                location: .outdoor)
              }
          }
          return INStartWorkoutIntentResponse(code: .success, userActivity: nil)
       }
    • 7:52 - App Delegate

      // Implement an app delegate
      
      // Create app delegate
      class WorkoutsOniOSSampleAppDelegate: NSObject, UIApplicationDelegate {
          let handler = IntentHandler()
      
          func application(_ application: UIApplication, handlerFor intent: INIntent) -> Any? {
              return handler
          }
      }
      
      // Add app delegate to app
      struct WorkoutsOniOSSampleApp: App {
          @UIApplicationDelegateAdaptor(WorkoutsOniOSSampleAppDelegate.self) var appDelegate
      
      }
    • 9:09 - Set up crash recovery

      // App Delegate
      
      func application(_ application: UIApplication,
                       configurationForConnecting connectingSceneSession: UISceneSession,
                       options: UIScene.ConnectionOptions) -> UISceneConfiguration {
          if options.shouldHandleActiveWorkoutRecovery {
              let store = HKHealthStore()
              store.recoverActiveWorkoutSession(completion: { (workoutSession, error) in
                  // Handle error
                  Task {
                      await WorkoutManager.shared.recoverWorkout(recoveredSession: workoutSession)
                  }
              })
          }
          let configuration = UISceneConfiguration(name: "Default Configuration", 
                                                   sessionRole: connectingSceneSession.role)
          configuration.delegateClass = WorkoutsOniOSSampleAppSceneDelegate.self
          return configuration
      }
    • 9:25 - Recover the workout session

      // Recover the workout for the session
      
      
      func recoverWorkout(recoveredSession: HKWorkoutSession) {
          session = recoveredSession
          builder = recoveredSession.associatedWorkoutBuilder()
          session?.delegate = self
          builder?.delegate = self
          workoutConfiguration = recoveredSession.workoutConfiguration
      
          let dataSource = HKLiveWorkoutDataSource(healthStore: healthStore,                                                                  
                                                   workoutConfiguration: workoutConfiguration)
          builder?.dataSource = dataSource
      }
    • 0:00 - 简介
    • HealthKit 框架支持健康和健身 App 访问集中管理的加密数据库,该数据库用于存储用户健康数据。借助该平台的体能训练 API,你可以为 iPhone 和 iPad 创建功能全面的体能训练 App,帮助用户跟踪体能训练数据、查看健康指标并获取恢复建议。了解如何运行体能训练会话、在体能训练期间访问各项指标、处理意外崩溃,以及提供有关体能训练的实用技巧和最佳实践。

    • 0:56 - 启动体能训练会话
    • 只需稍作调整,即可在 iPhone、iPad 和 Apple Watch 上使用相同的代码。要跟踪任何活动,你需要创建体能训练配置并设置其类型,然后开始会话。体能训练生成器会在体能训练过程中收集健康指标。

    • 2:50 - 获取体能训练指标
    • 在 Apple Watch 上进行体能训练时,设备内置的传感器可提供流畅的使用体验。相比之下,在 iPhone 或 iPad 上收集心率数据则需要与外部心率传感器配对,因为这些设备本身不具备该功能。 iPhone 和 iPad 可以收集各种体能训练指标,但系统生成的样本可能与 App 特别要求的样本不同。你可以修改体能训练过程中收集的默认数据类型。 用户保存体能训练数据后,你可以访问和显示一段时间内的摘要统计数据或图表指标。iPhone 体能训练可能包含针对某些指标的高精度细分数据,类似于历史 Apple Watch 体能训练数据。 iPhone 通常会在体能训练过程中锁定。出于隐私原因,设备处于锁定状态时,通常无法访问健康数据。不过,即使设备处于锁定状态,系统仍然可以提示用户授权 App 访问体能训练数据。然后,你可以在锁定屏幕上显示实时活动,无需用户解锁手机即可展示关键指标。 Siri 支持扩展至锁定屏幕,让用户无需动手即可开始、暂停、恢复或取消体能训练。你可以将 Siri 意图集成到你的 App 中,以实现这项功能。

    • 8:35 - 崩溃恢复
    • Apple Watch 上的崩溃恢复功能会自动重新启动 App 并恢复体能训练会话。对于 iPhone 和 iPad,新的场景委托负责在崩溃后恢复体能训练会话。你可以使用此 App 委托来检查恢复选项,并从健康数据储存库中检索已恢复的会话。

    • 9:34 - 最佳实践
    • 要通过 HealthKit 有效跟踪体能训练数据,可将在 Apple Watch App 中开始的体能训练镜像到 iPhone 中,仅需请求必要的数据授权,并使用 Workout Builder API 即可实现。借助这些建议,你可以确保健身记录圆环的准确更新,并进一步优化用户体验。此外,请务必升级到新的 API、下载示例 App,并考虑为 iPhone 和 iPad 添加体能训练支持,以扩大你的市场覆盖范围。

Developer Footer

  • 视频
  • WWDC25
  • 使用 iOS 和 iPadOS 上的 HealthKit 跟踪体能训练
  • 打开菜单 关闭菜单
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    打开菜单 关闭菜单
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    打开菜单 关闭菜单
    • 辅助功能
    • 配件
    • App 扩展
    • App Store
    • 音频与视频 (英文)
    • 增强现实
    • 设计
    • 分发
    • 教育
    • 字体 (英文)
    • 游戏
    • 健康与健身
    • App 内购买项目
    • 本地化
    • 地图与位置
    • 机器学习与 AI
    • 开源资源 (英文)
    • 安全性
    • Safari 浏览器与网页 (英文)
    打开菜单 关闭菜单
    • 完整文档 (英文)
    • 部分主题文档 (简体中文)
    • 教程
    • 下载 (英文)
    • 论坛 (英文)
    • 视频
    打开菜单 关闭菜单
    • 支持文档
    • 联系我们
    • 错误报告
    • 系统状态 (英文)
    打开菜单 关闭菜单
    • Apple 开发者
    • App Store Connect
    • 证书、标识符和描述文件 (英文)
    • 反馈助理
    打开菜单 关闭菜单
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program (英文)
    • News Partner Program (英文)
    • Video Partner Program (英文)
    • 安全赏金计划 (英文)
    • Security Research Device Program (英文)
    打开菜单 关闭菜单
    • 与 Apple 会面交流
    • Apple Developer Center
    • App Store 大奖 (英文)
    • Apple 设计大奖
    • Apple Developer Academies (英文)
    • WWDC
    获取 Apple Developer App。
    版权所有 © 2025 Apple Inc. 保留所有权利。
    使用条款 隐私政策 协议和准则