Manifest · 概念
已安装的 PWA 如何获取清单更新
发布于 更新于
已安装的 PWA 保留一份安装时所用清单的本地副本。Chrome 按计划重新抓取线上清单,与这份副本比较, 并且只在应用的所有窗口都关闭之后才应用变化。哪些字段触发重新检查、哪些字段随后被应用,桌面端 Chrome 与 Android 上的 Chrome 并不相同,而且桌面端路径完全无法更新图标。
这里记录的是 Chrome 的行为,由 Chrome 团队在 web.dev 的 How Chrome handles updates to the web app manifest 一文中描述;Edge 154 作为 Chromium 浏览器共用桌面端路径。Apple 没有为 Safari 27 的 主屏幕应用或 Dock 应用发布对应说明,Firefox 157 不从清单安装 Web 应用,所以本条目不对二者做 任何断言。
已安装应用的每次启动,以及在浏览器标签页里对站点的每次访问,都会让 Chrome 检查上一次比较清单的 时间。如果那是在浏览器上次启动之前,或者已经超过 24 小时,Chrome 就重新抓取清单。抓回的值与 本地相同时,计时器重置,不发生别的事。
在桌面端,name、short_name、display、scope、shortcuts、start_url、theme_color、
file_handlers 中任何一项发生变化都会把新清单排入队列;应用的每个窗口都关闭后安装新清单,然后
除 icons 之外的所有字段都被应用,桌面端 Chrome 不更新图标。此外还有两条规则:start_url 的
变化只在清单声明了 id 时才被应用,因为没有 id 时旧的 start_url 就是应用的身份;display
从 browser 改为 standalone 不会改变那些选择在标签页中打开应用的用户,用户的窗口偏好优先于
清单。
在 Android 上同样每 24 小时检查一次,但触发列表是 name、short_name、icons、
background_color、display、orientation、scope、shortcuts、start_url、theme_color
与 share_target,而应用变化意味着向 Google 的铸造服务器请求一个新的 WebAPK。Chrome 会等到
应用关闭、设备在充电且连接 Wi-Fi 之后才去请求;新 WebAPK 安装后,包括图标在内的每个字段都是
最新的。服务器不可达时 Chrome 会退避,最慢每 30 天检查一次。
重命名或移动清单文件会切断这条链:Chrome 重新抓取的是安装时的那个 URL,那里返回 404 就意味着 永远发现不了更新。保持清单 URL 稳定,只改它的内容。
前两个示例是清单改动及其对已安装用户的影响;第三个是如何不等一天就看到结果。
迁移启动 URL 而不产生第二个应用
Section titled “迁移启动 URL 而不产生第二个应用”团队把应用从 / 迁到 /app/。因为清单声明了 id,Chrome 把改过的清单视为同一个应用,在下一次
检查后应用新的 start_url;没有 id 的话,这个改动在桌面端会被忽略,已安装应用仍然启动 /。
{ "id": "/", "name": "Ledger", "start_url": "/app/?source=installed", "scope": "/", "display": "standalone"}在迁移之前、在一个不改别的东西的发布里先加上 id:id 必须已经存在于已安装的副本中,之后的
start_url 变化才会被识别。
更换主题色并知道用户何时能看到
Section titled “更换主题色并知道用户何时能看到”theme_color 在两份触发列表上都有,所以品牌换色无需重装就能到达已安装用户。时间线取决于检查
节奏,而不是部署时刻。
{ "name": "Ledger", "theme_color": "#0b5fff", "background_color": "#ffffff"}整天开着应用的桌面用户,要等某次检查发现变化、再关闭最后一个窗口之后才看到新颜色;Android 用户还需要充电加 Wi-Fi 才能让 WebAPK 重新铸造。预期是一两天,很少在 Wi-Fi 下充电的设备更久。
测试时强制触发更新检查
Section titled “测试时强制触发更新检查”Chrome 为开发者提供两条绕过 24 小时节流的路径:重启浏览器(about://restart 会重置计时器),
或带 --disable-manifest-update-throttle 启动。下面的脚本是应用内的配套检查:它把页面能抓到的
清单与烘进已安装 start_url 里的版本戳比较,告诉测试者已安装副本是否仍是旧的。
async function installedManifestIsStale() { const installedVersion = new URL(location.href).searchParams.get('v'); // 来自 start_url const live = await fetch('/manifest.webmanifest', { cache: 'no-store' }).then((r) => r.json()); const liveVersion = new URL(live.start_url, location.origin).searchParams.get('v'); if (!installedVersion || !liveVersion) return false; // 没有版本戳:无可比较 return installedVersion !== liveVersion;}页面读不到浏览器存储的副本;start_url 里的版本戳是页面唯一能观察到的已安装清单的一部分,
这也是为什么在 start_url 里加 ?v= 成了常见的测试约定。
- id 清单成员
- start_url 清单成员
- icons 清单成员
- WebAPK:Chrome 如何在 Android 上安装 PWA
- How Chrome handles updates to the web app manifest(web.dev)
- Uniquely identifying PWAs with the web app manifest id property(developer.chrome.com)
规范
| 规范 | 状态 |
|---|---|
| Web Application Manifest: id member | W3C |