苹果表上SleepTap的Smart Alarm的Session在Stop之后,对应的Smart Stack却没有立刻刷新问题的追踪
前天早上,SleepTap 的 Apple Watch Smart Alarm Session 把我叫醒了。系统界面给了两个选择,一个是 Open,一个是 Stop。以往我都是用Open,这次我特意没有选择Open,而是选择了 Stop。
Session 的确停了。但是我转动表冠打开 Smart Stack,发现 SleepTap 仍然显示 Wake Up。后来我手动进入 SleepTap,应用里已经没有 Wake Up 了。再回到 Smart Stack,它也变成了当晚 23:00 上床。
我当时认为,Stop 只是终止了 Session,其余步骤是在我进入应用后才执行的。这是我根据按下 Stop 后看到的现象作出的判断。但我并不确定,于是询问 AI。
Stop 到底做了什么?
AI和我讲,Apple Watch 的系统 Stop 会使 WKExtendedRuntimeSession 失效,然后调用:
extendedRuntimeSession(_:didInvalidateWith:error:)
SleepTap 收到这个回调以后,会检查 Session 是否正常结束、之前是否已经通过 notifyUser 叫醒用户,以及这次失效是不是应用自己触发的。如果这些条件都符合,就会把它当成用户点击了系统 Stop,自动记录起床。
记录起床以后,SleepTap 还会写入 HealthKit,清空本轮睡眠时间线,通知手机取消对应的起床闹钟,然后重新生成 Smart Stack 使用的数据,最后调用 reloadAllTimelines() 请求 WidgetKit 刷新。
这套后台路径本来就存在,并不是一定要打开应用。
不过代码里也的确有一个前台兜底。如果系统已经叫醒了用户,但是后台处理没有完成,那么用户下次进入 SleepTap 时,应用会再次检查状态并补记起床。这样一来,前天的现象其实存在两种解释:一种是后台处理没有完成,打开应用以后走了兜底;另一种是后台早就处理完了,只是 Smart Stack 还在显示旧内容,打开应用以后又请求了一次刷新。
只看 Smart Stack,根本分不清。于是我和AI说,那我再试一晚,明天不手动进应用,看看Smart Stack到底能不能更新。AI说,应该这么做,并且建议我分不同时段,多次观察,每次截图。
第二天的古法验证
今天的 Session 大约在凌晨 4:30 开始运行,我在 4:33 左右点击了 Stop。之后我一直没有打开 SleepTap。期间我多次观察,在几分钟后,半小时后都观察了,看到的都还是Wake Up。到了 5:33,我发现 Smart Stack 已经从 Wake Up 自动变成了 Bed Time 23:00。
这至少证明了一件事:不打开应用,后台链路也能完成。前台兜底并不是必需的。
但我很快又产生了另一个判断:难道 extendedRuntimeSession(_:didInvalidateWith:error:) 花了接近一个小时才执行?
我询问AI,AI建议我去看健康应用,根据健康应用的起床时间来辅助判断。
我打开健康 App,里面记录的起床时间是 4:33,和点击 Stop 的时间基本一致。SleepTap 在后台记录起床时,使用的是当时的当前时间。如果这段代码真的拖到 5:33 才执行,健康里的起床时间也应该接近 5:33,而不会是 4:33。
也就是说,Session 的失效回调和起床记录在 4:33 左右就已经完成了。延迟的不是业务处理,而是 Smart Stack 的显示。
这不叫回调执行了一小时,这叫 WidgetKit 一小时以后才把结果画出来。
当然,我只是在 5:33 才发现它发生了变化,并不能证明它正好延迟了一个小时。实际刷新时间位于我上一次查看和 5:33 之间。不过可以确认的是,在这段时间里,HealthKit 里的数据已经是正确的,而 Smart Stack 仍然可能显示旧的 Wake Up。
reloadAllTimelines() 这个名字很容易让人误会。看起来像是“立即重新加载所有 Timeline”,其实它只是向 WidgetKit 提交刷新请求。什么时候重新生成 Timeline,什么时候重绘,什么时候改变 Smart Stack 里的优先级,最终还是系统说了算。调用成功,不等于用户马上能看到结果。
这和我以前调查 Widget 问题时遇到的情况一样:共享数据已经变了,Widget 还在显示旧数据。很多时候不是数据没写进去,也不是业务代码没执行,而是 WidgetKit 继续保留了上一份 Timeline。
总结
这两天的调查结果已经很明确:
点击 Stop 后,Smart Alarm Session 会正常结束。SleepTap 的后台回调也会立即记录起床、写入 HealthKit,并更新 Smart Stack 使用的数据。打开应用只是兜底,不是完成这些操作的必要条件。
Smart Stack 最多可能在相当长的一段时间里继续显示旧的 Wake Up,但它最终会自行刷新。这是 WidgetKit 的可见状态延迟,不是 Session 延迟,也不是睡眠记录延迟。
一开始我根据界面判断后台代码没有执行。第二天又根据刷新时间判断回调执行了一个小时。两次判断都很合理,也都被健康数据推翻了。
所以,调查 Widget 问题,不能只看 Widget。界面是界面,数据是数据。把两者混在一起,肯定会追错方向。







