从 Google Fit 迁移到 Health Connect 意味着在 Android 上用 Health Connect 替换 Capacitor 应用中所有的 Fit API 调用,如果也发布到 iOS,则用 HealthKit 替换。Google 已于 2024 年 5 月 1 日停止接受新的 Fit 注册,且仅支持 Fit API 至 2026 年底。本指南将 Fit 数据类型和调用映射到 Health Connect,并展示替换用的 code @capgo/capacitor-health,以及涉及健康权限的 Play Console 审核流程。
Google Fit 弃用时间表
| 日期 | 事情经过 |
|---|---|
| 2024 年 5 月 1 日 | Google Fit API 不再接受新的开发者注册 |
| 2024 年至 2026 年 | 现有的 Fit 集成继续运行,Google 引导开发者转向 Health Connect |
| 2026 | Fit API(包括 REST API)已弃用 |
| 2026 年底 | 停止支持。Google 尚未公布确切的停用日期 |
Google 的迁移常见问题解答指出,没有与 Fit REST API 结构相同的替代方案:设备端应用将迁移到 Health Connect,云端集成将迁移到基于账户的 Google Health API。如果您在某处看到确切的停用日期,请在据此规划之前,先对照 Google 官方的常见问题解答进行核实。
迁移到 Health Connect 后有哪些变化
| Google Fit | Health Connect | |
|---|---|---|
| 数据存储位置 | Google 账号,云端存储 | 设备本地 |
| 身份验证 | 包含健身权限的 OAuth 2.0,Google Sign-In | 针对不同数据类型的 Android 运行时权限 |
| 配置 | Cloud 项目,OAuth 客户端,SHA-1 指纹 | Manifest 权限,隐私政策页面 |
| 可用性 | 任何支持 Play 服务的 Android 设备 | Android 14+ 内置,旧版本需从 Google Play 安装应用 |
| 历史记录 | 完整账户历史记录 | 默认最近 30 天,更早数据需 READ_HEALTH_DATA_HISTORY |
| Web/服务器访问 | REST API | 无(云端请使用 Google Health API) |
| iOS | 暂不支持 | 不支持,请使用 HealthKit |
| 应用商店审核 | 敏感权限的 OAuth 验证 | Play Console 中的 Health Connect 声明 |
最大的产品变化是以设备为中心的模式。一部手机上的 Health Connect 数据在另一部手机上不可见。如果你的应用需要跨设备显示历史记录,请将读数同步到你自己的后端。
将 Fit 数据类型映射到 Health Connect
| Google Fit 数据类型 | Health Connect 记录 | @capgo/capacitor-health 类型 |
|---|---|---|
com.google.step_count.delta |
StepsRecord |
steps |
com.google.distance.delta |
DistanceRecord |
distance |
com.google.calories.expended |
TotalCaloriesBurnedRecord / ActiveCaloriesBurnedRecord |
totalCalories / calories |
com.google.calories.bmr |
BasalMetabolicRateRecord |
basalCalories |
com.google.heart_rate.bpm |
HeartRateRecord |
heartRate |
com.google.weight |
WeightRecord |
weight |
com.google.height |
HeightRecord |
height |
com.google.body.fat.percentage |
BodyFatRecord |
bodyFat |
com.google.sleep.segment |
SleepSessionRecord 包含阶段 |
sleep |
com.google.oxygen_saturation |
OxygenSaturationRecord |
oxygenSaturation |
com.google.blood_pressure |
BloodPressureRecord |
bloodPressure |
com.google.blood_glucose |
BloodGlucoseRecord |
bloodGlucose |
com.google.body.temperature |
BodyTemperatureRecord |
bodyTemperature |
com.google.hydration |
HydrationRecord |
dietaryWater |
com.google.nutrition |
NutritionRecord |
dietaryEnergyConsumed (仅限能量) |
com.google.activity.segment 和 Sessions API |
ExerciseSessionRecord |
workouts (通过 queryWorkouts) |
无直接对应类型的 Fit 数据
- 心点 (
com.google.heart_minutes) 以及 移动分钟数 (com.google.active_minutes)是 Google Fit 的评分。Health Connect 存储原始数据,而非这些评分。请基于心率和锻炼会话自行计算指标。 - 活动样本 中按秒记录的活动类型,将由带片段的锻炼会话取代。
- 位置采样 在锻炼中的位置数据变为
ExerciseRouteHealth Connect 中的数据,这需要单独权限,且插件未暴露此功能。 - 节奏、速度和功率 存在于 Health Connect 中(
StepsCadenceRecord,SpeedRecord,PowerRecord),但插件的类型定义未涵盖。如果你依赖这些字段,编写一个小型自定义原生方法是最快的路径。
在编写 code 之前进行审计:列出所有 DataType 以及你调用的每个 API(History、Recording、Sessions、Sensors、Config、REST),并将每一项标记为已映射、已重算或已弃用。
步骤 1:移除 Google Fit
从你的 Android 项目和 JavaScript 中删除 Fit 集成:
- 移除
com.google.android.gms:play-services-fitness以及,如果仅用于 Fit,play-services-auth来自build.gradle. - 从 Google Cloud 中移除 Fit OAuth 客户端,并从你的同意屏幕中移除健身权限范围。
- 卸载你之前使用的旧版社区 Google Fit Capacitor 插件,然后运行
bunx cap sync.
在新版本上线之前,请将 Fit code 保留在分支中,以便在用户要求时导出历史数据。
步骤 2:安装健康插件
bun add @capgo/capacitor-health
bunx cap sync
@capgo/capacitor-health 支持 Capacitor 8,在 Android 上使用 Health Connect,在 iOS 上使用 HealthKit,并且需要 Android minSdk 26.
Android 配置
该插件会将其支持类型的 Health Connect 读写权限合并到您的 manifest 中,此外还有 <queries> Health Connect 包的 entry 以及权限说明 activity。您需要:
- 提供隐私政策。 Health Connect 会从权限面板中打开它。请添加
android/app/src/main/assets/public/privacypolicy.html,或在android/app/src/main/res/values/strings.xml:
<string name="health_connect_privacy_policy_url">https://example.com/privacy</string>
- 中设置 URL 精简权限。
tools:node="remove":
<uses-permission
android:name="android.permission.health.WRITE_BLOOD_GLUCOSE"
tools:node="remove" />
- 如需访问历史记录,请添加相应权限。 除非用户授权,否则 Health Connect 只能读取最近约 30 天的数据
READ_HEALTH_DATA_HISTORY:
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_HISTORY" />
iOS 配置
在 Xcode 中启用 HealthKit capability,并添加用途说明字符串到 Info.plist:
<key>NSHealthShareUsageDescription</key>
<string>Show your steps and workouts in the app.</string>
<key>NSHealthUpdateUsageDescription</key>
<string>Save the workouts you record in the app.</string>
步骤 3:检查可用性
Google Fit 在任何有 Play 服务的地方都能用。Health Connect 在 Android 13 及更早版本上可能没有,或者需要更新。
import { Health } from '@capgo/capacitor-health';
export async function ensureHealthAvailable() {
const result = await Health.isAvailable();
if (result.available) return true;
// On Android, send the user to install or update Health Connect
if (result.platform === 'android') {
await Health.openHealthConnectSettings();
}
console.warn('Health store unavailable:', result.reason);
return false;
}
在跳转前显示一个简短的说明页。从没听说过 Health Connect 的用户,看到 Play Store 突然打开会感到困惑。
步骤 4:用权限替换 OAuth
Fit 的流程是:Google 登录,请求健身 scope,然后调用 API。新流程只有一个权限弹窗:
const status = await Health.requestAuthorization({
read: ['steps', 'distance', 'calories', 'heartRate', 'sleep', 'workouts'],
write: ['weight'],
requestHistoryAccess: true, // Android only
});
if (status.readDenied.length > 0) {
// explain what will not work and offer openHealthConnectSettings()
}
if (status.historyAccessAvailable === false) {
// provider too old: only the last 30 days are readable
}
权限按数据类型划分,用户可以只授予其中一部分。使用 checkAuthorization 在每次应用启动时用相同的选项调用,因为用户随时可以在 Health Connect 设置里撤销授权。在 iOS 上,HealthKit 出于隐私会隐藏读取被拒的情况,所以空结果可能表示“没有数据”,也可能表示“没有权限”。
步骤 5:替换 History API 读取
一个 Fit readData 获取原始样本的调用变为 readSamples:
const end = new Date();
const start = new Date(end.getTime() - 24 * 60 * 60 * 1000);
const { samples } = await Health.readSamples({
dataType: 'heartRate',
startDate: start.toISOString(),
endDate: end.toISOString(),
limit: 500,
ascending: true,
});
for (const s of samples) {
console.log(s.startDate, s.value, s.unit, s.sourceName, s.deviceType);
}
sourceName 而在 Android 上, deviceType (watch, phone, chestStrap等)替代 Fit 的数据源对象。当手表和手机同时存在数据时,使用它们优先选择手表数据。
第 6 步:替换分桶与聚合读取
Fit 的 bucketByTime 加 aggregate 会变为 queryAggregated:
const { samples: daily } = await Health.queryAggregated({
dataType: 'steps',
startDate: new Date(Date.now() - 7 * 86_400_000).toISOString(),
endDate: new Date().toISOString(),
bucket: 'day', // 'hour' | 'day' | 'week' | 'month'
aggregation: 'sum',
});
const { samples: hr } = await Health.queryAggregated({
dataType: 'heartRate',
bucket: 'hour',
aggregation: ['min', 'average', 'max'],
startDate: new Date(Date.now() - 86_400_000).toISOString(),
endDate: new Date().toISOString(),
});
// hr[i].values.min, hr[i].values.average, hr[i].values.max
始终聚合步数,而不是对原始样本求和。Health Connect 在聚合过程中会去重来自多个应用的重复数据,而原始求和往往会在手表和手机同时记录步数时导致重复计算。
第 7 步:替换 Sessions API
Fit 会话映射到运动会话:
const { workouts, anchor } = await Health.queryWorkouts({
workoutType: 'running',
startDate: new Date(Date.now() - 30 * 86_400_000).toISOString(),
endDate: new Date().toISOString(),
limit: 50,
});
for (const w of workouts) {
console.log(w.workoutType, w.duration, w.totalDistance, w.totalEnergyBurned);
}
// pass `anchor` back to fetch the next page
请求 workouts 中的 read 先处理权限。该插件会读取锻炼数据,但不会写入运动记录,所以如果你的应用要记录锻炼,请写入底层样本(距离、卡路里、心率),并把运动记录本身保存在后端,或添加一个原生方法用于 ExerciseSessionRecord.
第 8 步:替换插入操作
Fit 的 insertData 会变为 saveSample:
await Health.saveSample({
dataType: 'weight',
value: 72.4, // kilograms
startDate: new Date().toISOString(),
});
await Health.saveSample({
dataType: 'bloodPressure',
value: 120,
systolic: 120,
diastolic: 80,
startDate: new Date().toISOString(),
});
值必须使用每种类型的默认单位(千克、米、千卡、bpm)。 metadata 该选项会被 Health Connect 忽略。
第 9 步:通过 Google Play 审核
健康权限会触发额外审核:
- 在 Play Console 中,打开 应用内容 并完成 健康应用 声明以及 Health Connect 权限表单。请为请求的每一项权限提供正当理由。
- 确保 Play Console 中链接的隐私政策与 Health Connect 界面中显示的隐私政策均说明了健康数据的使用方式。
- 更新 数据安全 表单:健康与健身数据,是否收集,是否共享。
- 提交仅声明已提供正当理由的权限的构建版本。额外声明的权限是最常见的被拒原因。
预留比常规更新更长的审核时间。将迁移作为独立版本发布,不要与无关功能混合。
第 10 步:迁移用户预期
- 告知用户其历史记录现在来自 Health Connect,且在授予历史访问权限之前,旧数据可能仅限于最近 30 天。
- 如果您的应用使用 Fit 进行云端同步,请现在将该职责转移到您的后端。
- 移除“连接 Google Fit”按钮,在 Android 上将其重命名为“连接 Health Connect”,在 iOS 上重命名为“连接 Apple Health”。
故障排除
isAvailable() 在 Android 13 上返回 false:Health Connect 未安装或版本过旧。请调用 openHealthConnectSettings().
权限弹窗从未出现:权限未在合并后的 manifest 中声明,或您已使用 tools:node="remove"的文件夹。请检查 android/app/build/intermediates/merged_manifests.
读取仅返回 30 天数据: 请求 requestHistoryAccess: true 并声明 READ_HEALTH_DATA_HISTORY.
步数总和高于 Google Fit:您累加了原始样本。请使用 queryAggregated.
iOS 上结果为空:要么没有数据,要么读取权限被拒绝。HealthKit 不会告诉你是哪种情况。
Play Console 拒绝该更新:移除未声明或无合理依据的 Health Connect 权限,并附上明确理由后重新提交。
分阶段发布迁移
原生部分(插件、manifest、HealthKit capability)需要发布商店版本。之后,查询、UI 和数据映射都是 JavaScript,你可以用 Live Updates 迭代。 Capgo 实时更新 同时让用户测试新流程。如果你还要读取实时传感器数据,请参阅我们的指南: 使用 Capacitor 构建心率监测仪,以及 健康插件文档 涵盖每种数据类型。