安装 · 平台
WebAPK
发布于
WebAPK 是用户在 Android 上安装 PWA 时由 Chrome 生成的一个很小的已签名 Android 包,让 web 应用拥有真正的包名、应用抽屉条目、设置 › 应用中的条目,以及针对其 scope 的 intent filter,而不只是一个主屏幕快捷方式。Chrome 57 引入了它;Samsung Internet 铸造自己的等价物;Firefox for Android 与 WebView 只安装快捷方式,桌面平台都不使用这一模型(兼容性数据集 webapk)。
安装经由 Google 的铸造服务完成,这也是 WebAPK 在安装时需要网络的原因:
- 用户从
beforeinstallprompt的prompt()、mini-infobar 或菜单接受安装。 - Chrome 把 manifest URL、解析后的内容与图标哈希发送给 WebAPK 服务器。
- 服务器返回一个用它自己的密钥签名的 APK,其中只有元数据:包名、标签、图标、启动画面,以及针对 manifest
scope的 intent filter。 - Chrome 通过 Android 的包安装器安装它;Android 把它当作应用对待,因此它出现在应用抽屉与设置 › 应用中,从两处都可以卸载。
服务器不可达时,Chrome 回退为普通的主屏幕快捷方式;页面在安装时无法得知走的是哪条路径,只能事后判断(见实测细节)。
与快捷方式相比,APK 带来的是系统级身份:
| 行为 | WebAPK | 主屏幕快捷方式 |
|---|---|---|
| 包名、应用抽屉、设置 › 应用条目 | 有(org.chromium.webapk.<hash>) |
无;仅主屏幕 |
从其他应用打开 scope 内的链接 |
在 WebAPK 中打开(intent filter) | 在浏览器中打开 |
| 启动画面 | 由 name、background_color 与 512 px 图标生成 |
无 |
| 最近任务条目 | 带应用名与 theme_color 的独立任务 |
浏览器任务 |
| 重复安装 | 不可能;复用已有的包 | 可能;重复项共用一份存储 |
| 安装时需要网络 | 是 | 否 |
web 内容仍然是 Chrome:WebAPK 在一个 Chrome activity 中用用户的 Chrome 配置文件启动 start_url,所以 Cookie、存储、service worker 与 Chrome 版本都是浏览器的。web 平台之外没有任何原生 API 变得可用,上架 Play 则需要改用 Trusted Web Activity。
manifest 更新
Section titled “manifest 更新”Chrome 在已安装应用启动时重新读取 manifest,当 name、short_name、icons、start_url、scope、display、orientation、theme_color 或 background_color 发生变化时向铸造服务器申请新的 APK;web.dev 的 WebAPKs 文章记载该检查被限制为大约一天一次,新 APK 在后台安装,因此改动会在之后的某次启动中显现。start_url 的源发生变化或 manifest 不再能解析时,更新会停止,而不是破坏已安装的应用。
两个示例都运行在页面中;第一个展示 WebAPK 在任何页面 JavaScript 之前就会绘制的内容,第二个按安装类型分支。
决定启动画面与任务卡片的 manifest 字段
Section titled “决定启动画面与任务卡片的 manifest 字段”启动画面由三个成员合成,显示到首次绘制为止;theme_color 为状态栏与最近任务卡片上色。缺少 background_color 时启动画面为白色,小于 512 px 的图标会被放大。
{ "name": "Trail Notes", "short_name": "Trails", "start_url": "/?source=webapk", "scope": "/", "display": "standalone", "background_color": "#101820", "theme_color": "#101820", "icons": [ { "src": "/icons/maskable-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }, { "src": "/icons/any-512.png", "sizes": "512x512", "type": "image/png" } ]}start_url 上的 ?source=webapk 查询参数是在统计中区分已安装应用启动次数的惯用做法;它也让已安装应用的第一个请求在服务器日志中可以辨认,否则它与标签页的请求完全相同。
检测已安装上下文与快捷方式回退
Section titled “检测已安装上下文与快捷方式回退”display-mode: standalone 在 WebAPK、manifest 要求 standalone 的快捷方式,以及 TWA 中都为 true,所以它回答“是否已安装”,却回答不了“哪种安装”。referrer 可以分出 TWA;排除掉 WebAPK 独有的 intent 捕获之后,剩下的就是快捷方式。
const standalone = matchMedia('(display-mode: standalone)').matches;const fromTwa = document.referrer.startsWith('android-app://');const launchedFromLink = new URL(location.href).searchParams.get('source') !== 'webapk' && standalone;
if (!standalone) { // 浏览器标签页:beforeinstallprompt 触发后可以显示安装界面。} else if (fromTwa) { // Play 分发的 TWA:可能有 Digital Goods API。} else if (launchedFromLink) { // 经 scope 的 intent filter 打开:只有 WebAPK 会这样。} else { // 从图标启动:WebAPK 或快捷方式;行为相同。}把最后两个分支同等对待是稳妥的选择:以快捷方式安装的用户拥有同样的 web 能力,只是少了系统集成,页面中不应有任何东西对他们失效。
- WebAPKs on Android(web.dev)
- Installation(web.dev)
- Trusted Web Activities overview(developer.chrome.com)
- WebAPK 浏览器支持
- Trusted Web Activity
- beforeinstallprompt 事件
- N+1 安装问题
- Chrome for Android 上的 PWA
规范
| 规范 | 状态 |
|---|---|
| WebAPK 可用性 | 厂商文档 |