Google Health API 使用 exercise 会话数据类型跟踪用户锻炼时段和锻炼记录。会话充当容器,用于捆绑活动元数据、暂停和恢复事件、圈数或分段数据以及摘要指标。
了解如何在应用中读取、写入和构建锻炼,以便为用户提供最佳体验。
支持的数据类型
该 API 支持以下数据类型,用于跟踪锻炼和活动会话:
数据类型dataType
filter 参数 |
记录 类型 |
可用 操作 |
范围 | 网络钩子 支持 |
真实零值 支持 |
|---|---|---|---|---|---|
锻炼
exerciseexercise
|
会话 | 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) :执行的活动类别(例如RUNNING、WALKING、BIKING或AEROBIC_WORKOUT)。指定确切的体育锻炼类型。 - 显示名称 (
displayName) :锻炼时段的易记名称(例如“下午越野跑”)。 - 活跃时长 (
activeDuration) :锻炼的真实活跃时间,不包括暂停间隔。标准格式使用Duration格式 (例如"1800s")。
摘要指标
metricsSummary 嵌套对象包含在整个锻炼时段内计算的总指标和平均指标:
caloriesKcal:锻炼期间消耗的总活跃卡路里数,以千卡 (kcal) 为单位。distanceMillimeters:覆盖的总距离,以毫米为单位,以保持各个单位之间的高精度。steps:锻炼期间采取的总步数。averageHeartRateBeatsPerMinute:用户在练习活跃分钟数内的平均心率。activeZoneMinutes:锻炼期间获得的累计活跃区间分钟数。averageSpeedMillimetersPerSecond:平均移动速度(毫米/秒)。averagePaceSecondsPerMeter:练习活跃分钟数内的平均配速,以秒/米为单位。elevationGainMillimeters:练习期间的总累计上升。
圈数和分段数据
对于涉及圈数的锻炼(例如跑道跑步或泳池游泳),请使用 splitSummaries。
每个分段数据都包含:
- 特定的
startTime和endTime。 - 表示真实圈数的
activeDuration。 - 仅限于该分段的
metricsSummary。 - 用于定义分块边界的
splitType(例如DISTANCE、DURATION或MANUAL)。
锻炼事件
如需准确计算活跃时长,请使用 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,而不是 startTime 和 endTime 之间的差值。这样可以防止暂停间隔扭曲指标。
例如,如果用户在 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 导入或写入已完成的锻炼时,请实现多步写入模式:
- 写入会话:通过向
POST /users/me/dataTypes/exercise/dataPoints发布数据点来提交摘要事件。 - 写入时间序列间隔:同时将锻炼期间记录的精细数据
点(例如每分钟步数或
卡路里消耗间隔)写入各自的集合:
POST /users/me/dataTypes/steps/dataPointsPOST /users/me/dataTypes/active-energy-burned/dataPointsPOST /users/me/dataTypes/heart-rate/dataPoints
查询图表的详细数据(读取路径)
为特定锻炼时段呈现历史锻炼信息中心或效果图表时,请使用会话的时间窗口查询精细遥测数据:
- 查询会话摘要:调用
/users/me/dataTypes/exercise/dataPoints以提取整体锻炼 详细信息和最终metricsSummary。 - 提取图表指标:检查锻炼的
interval.startTime和interval.endTime。针对该特定时间窗口对遥测集合进行辅助GET调用:GET /users/me/dataTypes/heart-rate/dataPoints?startTime=2026-04-20T08:00:00Z&endTime=2026-04-20T08:35:00Z
- 提取 GPS 路线:如果会话的元数据表明存在 GPS 数据(
exerciseMetadata.hasGps为true),请调用exportExerciseTcx帮助程序方法来下载路线坐标。