早上好,我是まさきん。
我把手机从 iPhone 换成了 Android。借这个机会,把健康数据的通道收拢成了一条。可唯独睡眠,在每天早上的通知里一直是“无记录来源”。原因出在 OAuth 的权限范围(scope)和重新授权同意上,所以连同官方信息一起记下来。
※以上为文章发布时的信息。最新条件请以官方网站为准。
- Google Health API 的睡眠,要用和步数不同的权限范围
sleep.readonly来读取 - 权限范围是后加的话,手上的令牌并不会多出权限。需要重新做一次授权同意
- 在授权URL里加上
include_granted_scopes=true,就能把之前许可过的权限范围一并继承下来 - 修没修好,可以先用不写入正式环境的试运行来确认
- 加权限之前的大约一周,在我这里没能回溯补上
当时出现的症状
我的健康数据,现在是沿着这样一条路径流动的。从运动手环到 Google 的健康应用(Google Health)。再从那里经过 API,进到我自己的记录(健康日志)。就这一条。
步数之类的,早就能导入了。可唯独睡眠那一栏填不上。每天早上收到的通知里,睡眠那里显示的是“无记录来源”。
原因是后来才加的权限范围
原因很简单。睡眠用的权限,是我后来才加的。
最初同意授权的时候,请求的是步数之类的权限范围。之后,我在代码里补写了睡眠的权限范围。但是,授权同意并没有重新做。
Google Health API 的官方文档里是这么写的:签发的访问令牌里包含的,只有同意授权的用户许可过的权限范围。也就是说,光在代码里补写一笔,什么都不会变。
Google Health API 这个名字
Google Health API 在官方的说明里是“Fitbit Web API 的下一代版本”。它是在 Google 的 OAuth 2.0 之上处理 Fitbit、Pixel Watch 等数据的机制。
原来的 Fitbit Web API 已经公布了终止的日程。支持终止是2026年9月30日。API 本身停用是2026年10月30日。要想继续获取数据,官方引导的是迁移到 Google Health API。
不过,同一份说明里还有一条注意事项。大意是目前不接受新的项目。打算现在才开始的话,先看一下官方最新的说明,也许会比较安心。
区分症状和原因
把“唯独拿不到睡眠”时可能的原因列成表。
| 症状 | 可能的原因 | 去哪里确认 |
|---|---|---|
| 只有睡眠是空的 | 没有同意睡眠的权限范围 | 令牌里包含的权限范围 |
| 所有项目突然都拿不到 | 令牌失效(401) | 发布状态和失效条件 |
| 同意成功了,调用却失败 | 账号没有关联 Google Health | Google Health 应用的设置 |
| 只有特定的日子是空的 | 那一天的记录在 Google 那边不存在 | Google Health 应用里的显示 |
我的情况是最上面那一行。步数能拿到,说明令牌本身还是活着的。
全部停掉的那种情况,我另外写了一篇文章。
Google的刷新令牌7天就过期,原因是“测试中”:发布到正式环境的步骤
如果原因出在发布状态上,我觉得那篇更接近。
睡眠数据的权限范围和数据类型
Google Health API 的权限范围,全都以同一个字符串开头,也就是 https://www.googleapis.com/auth/googlehealth。在它后面,接上各个数据分组的名字。
我从官方的权限范围列表和数据类型页面里,把这次相关的部分摘了出来。
| 权限范围(末尾) | 官方的说明 | 能读取的数据示例 |
|---|---|---|
.activity_and_fitness.readonly | 查看活动和健身数据 | 步数等活动数据 |
.sleep.readonly | 查看睡眠数据 | 睡眠会话和睡眠阶段 |
.health_metrics_and_measurements.readonly | 查看健康指标和测量数据 | 睡眠中的心率变异性、呼吸频率等 |
睡眠的数据类型是 sleep,记录的单位是会话。一次睡眠里,排列着各个阶段的区间。阶段有 LIGHT / DEEP / REM / AWAKE 四种。
我放进健康日志的,是睡眠时长、深度睡眠和快速眼动睡眠。这些都是 .sleep.readonly 范围内就能读到的数据。
另一方面,睡眠中的心率变异性和血氧就不一样了。它们归在健康指标的权限范围里。用“睡眠”这个词一概而论的话,这里可能就会弄错。
官方的引导是只请求必要的权限范围。写入的权限范围,只在要发送数据时才设置。如果只是读取,readonly 看来就够了。
追加权限范围时的 OAuth 规则
即使刷新手上的刷新令牌,权限也不会增加。刷新得到的,是已经许可的范围内的访问令牌。
要用上新的权限范围,路只有一条。重新发送一次包含该权限范围的授权请求。用户在同意画面上许可。到这一步,新的权限才会加上。
增量授权和 include_granted_scopes
事后追加权限范围的做法,在官方有一个名字,叫增量授权(incremental authorization)。也就是在需要的时候,才去请求追加的权限范围。
这时要用到的,是 include_granted_scopes 这个参数。把值设为 true 并通过同意之后,新的访问令牌也会包含以前的权限范围。官方把它作为最佳实践来推荐。
官方还写了合并后授权的规则。使用那个刷新令牌,就能得到涵盖全部权限范围的访问令牌。反过来,一旦撤销,包含在内的权限范围会同时全部失效。
也就是说,只追加睡眠的时候,也不会丢掉步数的权限。
刷新令牌的处理
如果是自动运行的工具,就需要刷新令牌。把授权URL里的 access_type 设为 offline,就是为此做的指定。
官方还有一条很重要的说明。刷新令牌只会在第一次交换授权码时返回。第二次及以后的同意,有可能不会返回。
想确保拿到新的刷新令牌时,就加上 prompt=consent。这是让同意画面每次都出现的指定。在重新授权同意的场合,加上它也许更不容易迷糊。
重新授权同意的步骤
把一般的流程按编号整理一下。是照着面向 Web 服务器的 OAuth 2.0 官方步骤来的。
- 在 Google Cloud 控制台里,确认打开的是目标项目
- 在工具这边的权限范围列表里补写
.sleep.readonly - 拼出授权URL。在
scope里列出需要的权限范围 - 在同一个URL里加上
access_type=offline和include_granted_scopes=true - 如果要重新获取刷新令牌,再加上
prompt=consent - 由本人在浏览器里打开这个URL,在同意画面上看清内容后许可
- 把返回的授权码交换成令牌
- 确认响应的
scope里有没有睡眠的权限范围 - 保存新的刷新令牌,旧的不再使用
第8步虽然不起眼,却是很重要的一步。在同意画面上,用户可以逐个权限范围选择是否许可。
交给AI的工作和自己做的操作
这次的前期准备,是让AI(Claude)在 Mac 上做的。比如准备好加了权限范围的授权URL。我做的,是打开同意画面按下许可。
| 工作 | 负责 | 理由 |
|---|---|---|
| 准备加了权限范围的授权URL | AI(Claude) | 是字符串拼接,容易出错 |
| 打开同意画面按下许可 | 我 | 因为这本身就是本人的意思表示 |
| 看第二天早上的通知 | 我 | 最后想用自己的眼睛确认 |
同意,是数据的主人表示“可以交出去”的操作。所以,只有按下许可这一步,我是自己来做的。
每天早上通知的机制,写在另一篇文章里。
换了手机,这些联动就得一个一个重新检查。趁着同一个时机,把每月的通信费也重新看一看怎么样?
用试运行来确认
重新授权同意之后,我没有马上跑正式流程。先做试运行。也就是不写入正式记录、只试着获取的一次执行。
在试运行里,确认了睡眠数据能返回。然后才走了正式的处理。健康日志当天那一行里,填进了三个值:睡眠时长、深度睡眠,还有快速眼动睡眠。看到这里,才算完成。
试运行的话,就算失败也不会弄脏任何东西。用空值覆盖已有行这种事故,可以提前防住。
确认的顺序是先做只读取的试运行,再往正式记录里写。只要定好不把这个顺序反过来,即使刚重新授权完,也能不慌不忙地往下走。
没能回溯的大约一周
只有一样东西没能找回来。那就是加权限之前大约一周的睡眠。
这段时间,Google 那边也没有记录。所以,即使重新授权同意也填不上。健康日志里的那几行,我就让它空着。
我没有往空行里填推测的值。因为之后回头看的时候,会和真实的记录分不清。我觉得“没有就是没有”地留下来,作为日志才更诚实。
权限通了,如果原始记录不存在,也什么都不会返回。排查的时候,先看应用那边的显示会比较快。
如果打算追加权限范围,把追加的日期记下来也不错。以后看到空着的那段时间,马上就能想起原因。
健康数据的权限范围分量很重
健康数据是敏感信息。在 Google 那边,对待它也更严格。
官方写着,Google Health API 的权限范围大部分属于“受限”。面向公众发布的应用,需要通过审核。审核分两个阶段:OAuth 应用的验证,以及由第三方进行的安全评估。
没有通过审核的应用,用户数被限制在100人以内。如果是只给自己用的工具,看来基本不会碰到这个上限。不过,在同意之前有时会出现未验证应用的警告。
常见的失误和陷阱
| 失误 | 会发生什么 | 怎么防 |
|---|---|---|
| 在代码里加了权限范围就满足了 | 令牌的权限不会变 | 加了就重新授权同意 |
| 刷新令牌没有返回 | 一直用着旧令牌 | 加上 prompt=consent 重新获取 |
| 一上来就在正式环境里试 | 用空值覆盖记录 | 先跑一遍试运行 |
| 用推测去填空白的时段 | 和真实的记录分不清 | 就让它空着 |
事先做成了会在通知里显示“无记录来源”的设计,这一点帮了忙。
开始之前要确认的事
- 用的 API 是 Google Health API 还是原来的 Fitbit Web API
- 控制台里打开的是不是目标项目
- 想追加的数据归在哪个权限范围里
- 现在的令牌里包含哪些权限范围
- 发布状态是测试中还是正式环境
- 授权URL里有没有加上 include_granted_scopes 和 access_type
- 能不能留出让本人打开同意画面的时间
- 有没有不写入正式环境的试运行手段
发布状态如果一直是“测试中”,刷新令牌7天就会失效。即使加了权限范围并重新同意,这个期限也照样另外起作用。先看一下发布状态,也许就能避免白跑一趟。
常见问题
Q. 加了权限范围之后,一定要重新同意吗?
是的,需要。因为令牌里包含的,只有用户许可过的权限范围。光在代码或设置里加上,权限是不会增加的。
Q. 刷新一下刷新令牌,新的权限范围也会加上吗?
不会。刷新得到的,是已经许可的范围内的访问令牌。新的权限范围,要在同意画面上许可之后才会加上。
Q. 睡眠数据要用哪个权限范围来读取?
在 Google Health API 里是 .sleep.readonly。可以读到睡眠会话和其中的各个阶段。睡眠中的心率变异性之类,需要另外的健康指标权限范围。
Q. 能拿到深度睡眠和快速眼动睡眠吗?
官方的数据类型里,阶段有四种:LIGHT / DEEP / REM / AWAKE。不同机型的支持情况不一样,所以把官方的支持机型表也看一下会更稳妥。
Q. 同意之前那些天的睡眠,能回溯获取吗?
我觉得取决于原始记录在 Google 那边有没有。我的情况是,大约一周的记录在 Google 那边也不存在。所以,那段时间就一直空着。
Q. 连同意的操作都交给 AI 可以吗?
我没有交。因为我认为同意是数据主人本人的意思表示。交给 AI 的,只到准备授权URL之类的前期准备为止。
Q. 继续用 Fitbit Web API 也可以吗?
官方的说明是将于2026年10月30日停用。要继续获取数据,就需要迁移到 Google Health API。新项目的受理情况,请以官方的说明为准。
参考的官方信息
- Google Health API(Google for Developers)
- Google Health API 的权限范围(Google for Developers)
- Sleep and recovery 数据类型(Google for Developers)
- App verification(Google Health API)
- Troubleshooting(Google Health API)
- 在 Web 服务器应用中使用 OAuth 2.0(Google for Developers)
- 使用 OAuth 2.0 访问 Google API(Google for Developers)
总结
唯独睡眠显示“无记录来源”,原因是后来才加的权限范围。加了,就重新授权同意。弄明白之后,就只是这么一回事。
前期准备交给了 AI,按下许可这一步是我自己做的。用试运行确认之后,才跑的正式流程。修没修好的最终确认,是第二天早上的通知。这正是接下来要看的。
如果刚换了手机,不妨把已经联动的应用的权限过目一遍。
如果也在考虑换运营商,还有一篇整理了MNP携号转网步骤的文章。
本文包含联盟营销广告。如果您通过本站链接申请相关商品或服务,我们可能会从合作企业获得报酬。此外,运营者是乐天集团的员工,也可能通过员工推荐计划获得报酬。文章内容与评价均基于运营者的真实体验与调查完成,与是否存在广告无关,但请您在阅读前了解上述关系。详情请参阅免责声明与联盟营销说明。 免责声明与联盟营销说明
本文包含机器翻译内容。正式条件请以乐天移动官方网站的多语言页面为准。
如果您对乐天移动的通信区域·信号状况有疑问,可以通过官方的 电波改善调查申请表 进行咨询。