使用 Google Health API 开发锻炼体验

Google Health API 使用 exercise 会话数据类型跟踪用户锻炼时段和锻炼记录。会话充当容器,用于捆绑活动元数据、暂停和恢复事件、圈数或分段数据以及摘要指标。

了解如何在应用中读取、写入和构建锻炼,以便为用户提供最佳体验。

支持的数据类型

该 API 支持以下数据类型,用于跟踪锻炼和活动会话:

表:Google Health API 锻炼数据类型
数据类型
  dataType
  filter 参数
记录
类型
可用
操作
范围 网络钩子
支持
真实零值
支持
锻炼
  exercise
  exercise
会话 list、get、reconcile、create、update、batchDelete activity_and_fitness

虽然锻炼时段使用 exercise 数据类型作为容器,但典型的锻炼跟踪器会在会话期间写入和读取详细的高频遥测数据。这些测量值(例如心率或步数)必须使用各自的数据类型进行读取或写入。

下表将 exercise 数据类型的 metricsSummary 对象中的字段映射到 Google Health API 的相应原始遥测数据类型:

摘要字段 (metricsSummary) 日内遥测数据类型名称 API 遥测数据类型 ID
caloriesKcal 活动消耗的能量 active-energy-burned
distanceMillimeters 距离 distance
steps 步数 steps
averageHeartRateBeatsPerMinute 心率 heart-rate
activeZoneMinutes 活跃区间分钟数 active-zone-minutes

以下部分提供了 exercise 数据类型的技术详细信息,包括 REST 表示法示例、GPS 路线处理和集成指南。

锻炼时段

将每日活动或锻炼写入为 exercise 会话数据点。每个数据点都描述了整个会话,详细说明了事件间隔(例如暂停和恢复操作),并提供了摘要指标(例如总距离、步数和平均心率)。

会话属性

构建锻炼数据点时,请验证以下核心组件:

  • 会话时间 (interval) :整个锻炼时段的开始时间和结束时间,以及这些时间点处于活跃状态的时区偏移量。
  • 活动类型 (exerciseType) :执行的活动类别(例如 RUNNINGWALKINGBIKINGAEROBIC_WORKOUT)。指定确切的体育锻炼类型。
  • 显示名称 (displayName) :锻炼时段的易记名称(例如“下午越野跑”)。
  • 活跃时长 (activeDuration) :锻炼的真实活跃时间,不包括暂停间隔。标准格式使用 Duration 格式 (例如 "1800s")。

摘要指标

metricsSummary 嵌套对象包含在整个锻炼时段内计算的总指标和平均指标:

  • caloriesKcal:锻炼期间消耗的总活跃卡路里数,以千卡 (kcal) 为单位。
  • distanceMillimeters:覆盖的总距离,以毫米为单位,以保持各个单位之间的高精度。
  • steps:锻炼期间采取的总步数。
  • averageHeartRateBeatsPerMinute:用户在练习活跃分钟数内的平均心率。
  • activeZoneMinutes:锻炼期间获得的累计活跃区间分钟数。
  • averageSpeedMillimetersPerSecond:平均移动速度(毫米/秒)。
  • averagePaceSecondsPerMeter:练习活跃分钟数内的平均配速,以秒/米为单位。
  • elevationGainMillimeters:练习期间的总累计上升。

圈数和分段数据

对于涉及圈数的锻炼(例如跑道跑步或泳池游泳),请使用 splitSummaries

每个分段数据都包含:

  • 特定的 startTimeendTime
  • 表示真实圈数的 activeDuration
  • 仅限于该分段的 metricsSummary
  • 用于定义分块边界的 splitType(例如 DISTANCEDURATIONMANUAL)。

锻炼事件

如需准确计算活跃时长,请使用 exerciseEvents 跟踪状态转换(例如手动或自动暂停事件)。

每个事件都包含时间戳 (eventTime) 和类型:

  • START / STOP:表示用户明确开始或停止记录时的边界时间戳。
  • PAUSE / RESUME:表示会话何时手动暂停或恢复。
  • AUTO_PAUSE / AUTO_RESUME:表示传感器驱动的自动暂停/恢复。

写入锻炼时段

如需创建、更新或导入锻炼时段,请将数据点写入 exercise 数据类型集合。使用 create 数据点端点。

REST 表示法示例

以下示例展示了如何使用 POST 方法写入锻炼时段:

请求

POST https://health.googleapis.com/v4/users/me/dataTypes/exercise/dataPoints
Authorization: Bearer access-token
Content-Type: application/json

{
  "dataSource": {
    "recordingMethod": "ACTIVELY_MEASURED"
  },
  "exercise": {
    "interval": {
      "startTime": "2026-04-20T08:00:00Z",
      "startUtcOffset": "0s",
      "endTime": "2026-04-20T08:35:00Z",
      "endUtcOffset": "0s"
    },
    "exerciseType": "RUNNING",
    "displayName": "Morning Trail Run",
    "activeDuration": "1800s",
    "metricsSummary": {
      "caloriesKcal": 380.0,
      "distanceMillimeters": 5000000.0,
      "steps": "6200",
      "averageSpeedMillimetersPerSecond": 2777.78,
      "averagePaceSecondsPerMeter": 360.0,
      "averageHeartRateBeatsPerMinute": "148",
      "activeZoneMinutes": "30"
    },
    "exerciseMetadata": {
      "hasGps": true
    },
    "exerciseEvents": [
      {
        "eventTime": "2026-04-20T08:15:00Z",
        "eventUtcOffset": "0s",
        "exerciseEventType": "PAUSE"
      },
      {
        "eventTime": "2026-04-20T08:20:00Z",
        "eventUtcOffset": "0s",
        "exerciseEventType": "RESUME"
      }
    ],
    "splitSummaries": [
      {
        "startTime": "2026-04-20T08:00:00Z",
        "startUtcOffset": "0s",
        "endTime": "2026-04-20T08:15:00Z",
        "endUtcOffset": "0s",
        "splitType": "DISTANCE",
        "metricsSummary": {
          "distanceMillimeters": 2500000.0,
          "caloriesKcal": 190.0
        }
      }
    ]
  }
}

响应

{
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.devicesandservices.health.v4main.DataPoint",
    "name": "users/me/dataTypes/exercise/dataPoints/morning-trail-run-123456",
    "dataSource": {
      "recordingMethod": "ACTIVELY_MEASURED",
      "application": {
        "packageName": "com.example.workoutapp"
      },
      "platform": "GOOGLE_WEB_API"
    },
    "exercise": {
      "interval": {
        "startTime": "2026-04-20T08:00:00Z",
        "startUtcOffset": "0s",
        "endTime": "2026-04-20T08:35:00Z",
        "endUtcOffset": "0s"
      },
      "exerciseType": "RUNNING",
      "displayName": "Morning Trail Run",
      "activeDuration": "1800s",
      "metricsSummary": {
        "caloriesKcal": 380.0,
        "distanceMillimeters": 5000000.0,
        "steps": "6200",
        "averageSpeedMillimetersPerSecond": 2777.78,
        "averagePaceSecondsPerMeter": 360.0,
        "averageHeartRateBeatsPerMinute": "148",
        "activeZoneMinutes": "30"
      },
      "exerciseMetadata": {
        "hasGps": true
      },
      "exerciseEvents": [
        {
          "eventTime": "2026-04-20T08:15:00Z",
          "eventUtcOffset": "0s",
          "exerciseEventType": "PAUSE"
        },
        {
          "eventTime": "2026-04-20T08:20:00Z",
          "eventUtcOffset": "0s",
          "exerciseEventType": "RESUME"
        }
      ],
      "splitSummaries": [
        {
          "startTime": "2026-04-20T08:00:00Z",
          "startUtcOffset": "0s",
          "endTime": "2026-04-20T08:15:00Z",
          "endUtcOffset": "0s",
          "activeDuration": "900s",
          "splitType": "DISTANCE",
          "metricsSummary": {
            "distanceMillimeters": 2500000.0,
            "caloriesKcal": 190.0
          }
        }
      ]
    }
  }
}

GPS 路线和位置跟踪

该 API 直接在 exercise 数据点内保存基本会话摘要,但将详细的位置记录和 GPS 路线坐标作为单独的数据流处理。

如需下载户外会话的详细路线数据,请调用 exportExerciseTcx 自定义方法。此端点以行业标准的训练中心 XML (TCX) 格式返回路线。

导出 GPS 路线

请求

GET https://health.googleapis.com/v4/users/me/dataTypes/exercise/dataPoints/exercise-data-point-id:exportExerciseTcx?alt=media
Authorization: Bearer access-token

响应

一个 HTTP 有效负载,其中包含 Content-Type: application/tcx+xml 和 指示浏览器保存文件的标头。

<?xml version="1.0" encoding="UTF-8"?>
<TrainingCenterDatabase xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2">
  <Activities>
    <Activity Sport="Running">
      <Id>2026-04-20T08:00:00Z</Id>
      <Lap StartTime="2026-04-20T08:00:00Z">
        <TotalTimeSeconds>1800</TotalTimeSeconds>
        <DistanceMeters>5000</DistanceMeters>
        <Calories>380</Calories>
        <Intensity>Active</Intensity>
        <TriggerMethod>Manual</TriggerMethod>
        <Track>
          <Trackpoint>
            <Time>2026-04-20T08:00:00Z</Time>
            <Position>
              <LatitudeDegrees>37.7749</LatitudeDegrees>
              <LongitudeDegrees>-122.4194</LongitudeDegrees>
            </Position>
            <AltitudeMeters>15.0</AltitudeMeters>
            <DistanceMeters>0.0</DistanceMeters>
          </Trackpoint>
        </Track>
      </Lap>
    </Activity>
  </Activities>
</TrainingCenterDatabase>

必需的范围和位置

如需读取或写入 GPS 路线和位置跟踪的数据,请在应用的访问令牌中请求以下 OAuth 范围:

  • 读取权限https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonly
  • 写入权限https://www.googleapis.com/auth/googlehealth.activity_and_fitness.writeonly
  • 读取权限https://www.googleapis.com/auth/googlehealth.location.readonly

如果授权标头中缺少必需的范围,Google Health API 会返回授权错误。

指南

将锻炼跟踪功能集成到应用中时,请遵循以下设计和实现指南。

活跃时长与总时长

如需计算速度或配速指标,请始终使用 activeDuration,而不是 startTimeendTime 之间的差值。这样可以防止暂停间隔扭曲指标。

例如,如果用户在 08:00 开始锻炼,并在 08:35 结束锻炼,则锻炼的总用时为 2,100 秒。如果用户暂停锻炼 5 分钟(300 秒),请将 activeDuration 设置为 "1800s" (2,100 - 300)。该 API 使用活跃时长来计算平均值,即将总距离除以 1,800 秒,而不是 2,100 秒。

尽早请求位置信息

如果您的应用会绘制锻炼路线,请请求位置权限和 Google Health location 范围,以及活动和健身范围。在查看 GPS 锻炼时,向用户说明您的应用为何需要位置范围。

当您的应用请求位置范围 (https://www.googleapis.com/auth/googlehealth.location.readonly) 时,Google OAuth 会向用户显示权限请求提示。向用户说明,此权限对于呈现路线叠加层和导出 GPS 轨迹文件 (TCX) 是必需的。如果用户授予了活动范围但拒绝了位置信息权限,exportExerciseTcx 会返回授权错误,但您仍然可以在 metricsSummary 中访问会话汇总。

使用网络钩子进行实时同步

订阅 exercise 数据类型,以便在有新的锻炼数据可用时使用网络钩子通知后端。这样,您就可以实时触发锻炼后体验。

当服务器收到网络钩子通知时,其中包含 healthUserId 和锻炼的具体实际时间间隔。服务器应异步处理通知,然后从 /users/me/dataTypes/exercise/dataPoints 端点请求新的 exercise 数据点。如需详细了解如何设置订阅,请参阅 网络钩子订阅

保持指标一致

如需提供完整的锻炼体验,您的应用必须同步高频遥测数据点以及整个 exercise 会话。 这样可确保用户的每日总计、历史趋势和详细图表保持完全一致。

同步遥测和会话(写入路径)

向 Google Health API 导入或写入已完成的锻炼时,请实现多步写入模式:

  1. 写入会话:通过向 POST /users/me/dataTypes/exercise/dataPoints发布数据点来提交摘要事件。
  2. 写入时间序列间隔:同时将锻炼期间记录的精细数据 点(例如每分钟步数或 卡路里消耗间隔)写入各自的集合:
    • POST /users/me/dataTypes/steps/dataPoints
    • POST /users/me/dataTypes/active-energy-burned/dataPoints
    • POST /users/me/dataTypes/heart-rate/dataPoints

查询图表的详细数据(读取路径)

为特定锻炼时段呈现历史锻炼信息中心或效果图表时,请使用会话的时间窗口查询精细遥测数据:

  1. 查询会话摘要:调用 /users/me/dataTypes/exercise/dataPoints以提取整体锻炼 详细信息和最终 metricsSummary
  2. 提取图表指标:检查锻炼的 interval.startTimeinterval.endTime。针对该特定时间窗口对遥测集合进行辅助 GET 调用:
    • GET /users/me/dataTypes/heart-rate/dataPoints?startTime=2026-04-20T08:00:00Z&endTime=2026-04-20T08:35:00Z
  3. 提取 GPS 路线:如果会话的元数据表明存在 GPS 数据(exerciseMetadata.hasGpstrue),请调用 exportExerciseTcx 帮助程序方法来下载路线坐标。