网页应用靠定时器、轮询与同步保活——聊天跳动、看板刷新、上传完成、令牌续期。可一旦应用切到后台,WebView 这份契约就断了。Android 的 WebView 在 activity 暂停时会暂停 JavaScript;pauseTimers() 会冻结整个进程的每一个定时器;而在 iOS 上,苹果工程师在官方论坛明确确认:WKWebView 的 JavaScript 在应用进入后台时会「直接暂停/冻结」——这是设计使然。WebView 没有 Background Fetch、没有 Background Sync、没有保活机制。宿主自有 runtime 提供真正的后台任务桥——原生调度、服务端推送的差量、以及前台检查点——让体验在应用退到后台后依然存活。
应用退到后台,页面随之中断
在 Android 上,WebView.onPause() 会暂停动画与定位;官方生命周期实践还会搭配 pauseTimers(),它会「停止所有 WebView 的布局、解析与 JavaScript 定时器」,而且是全局生效。应用一旦进入后台,setInterval 回调、fetch 重试、长任务全部停止触发。iOS 的回答更直接:苹果开发者论坛上一位框架工程师表示,这是「设计使然,原因和任何被挂起的应用不再执行代码一样」,自 iOS 13 起仅保留「几秒钟」的宽限。WKWebView 甚至必须挂在视图层级里才能运行 JavaScript,离屏或后台的实例会直接空闲停摆。
没有后台抓取,也没有后台同步
Web 平台应对「先离线、再恢复」的方案——Background Fetch、Background Sync、Periodic Background Sync——在 WebView 里统统缺席。即便独立浏览器支持,WebView 也不会把它们桥接到操作系统。于是,一个把失败上传「排队等联网再重试」的 H5 没有任何东西能唤醒它;一个每三秒轮询的聊天直接停摆;用 setTimeout 安排的令牌续期会晚点甚至永不触发。
页面被冻结时,你会失去什么
- 实时性停摆。 用户一切走开,聊天、在线状态、实时看板立刻停止更新。
- 上传与同步中断。 进行中的请求与排队写入永远无法完成或重试。
- 令牌静默过期。 页面内安排的续期晚几小时才触发,而会话早已死亡。
- 重试循环死亡。 指数退避定时器被冻结,只能等下次打开才恢复。
- 无离线优先保证。 Service Worker 后台同步在 WebView 里不可用(见「沉默的信箱」篇),页面也无从弥补。
runtime 解法
宿主自有 runtime 把后台工作从页面剥离。它在 WebView 之下提供原生任务桥:宿主通过平台的后台任务 API 调度有界的后台工作,在前台时把差量推给页面,并在应用挂起前检查点保存状态。H5 在前台仍用它的定时器,但 runtime 保证工作真正发生——可恢复、可观测,不再听命于引擎的空闲暂停。
| 维度 | WebView | 宿主自有 runtime |
|---|---|---|
| 后台 JS | 按设计冻结 | 原生调度 |
| 定时器(setInterval) | 暂停时停止 | 桥接在前台恢复 |
| Background Fetch / Sync | 不可用 | 服务端推送差量 |
| iOS WKWebView | 挂起,仅数秒宽限 | 宿主任务,独立 |
| 上传 / 同步重试 | 后台中断 | 排队 + 恢复 |
| 状态检查点 | 无 | 挂起 / 恢复时保存 |
浏览器标签页可以指望平台保活它的工作。原生 WebView 不行。runtime 给页面一个可信的后台——退到主屏,不再意味着一片漆黑。
参考来源
- Apple Developer 论坛 — WKWebView 在后台时的 JavaScript 执行 — 苹果工程师:挂起「设计使然」。
- AOSP — WebView 生命周期最佳实践(第 45 章) — onPause/pauseTimers 冻结所有 JS 定时器。
- Stack Overflow — WKWebView 在后台不运行 JavaScript — WebView 必须处于视图层级才能执行。
- MDN — Background Synchronization API — WebView 未桥接的 Web 方案。
- Apache Cordova — WKWebView 中后台 JS 不可靠 — iOS 暂停,Android 不保证。