平台 · 平台
Chrome 与 Android 上的 PWA
发布于 更新于
在搭载 Google Mobile Services(GMS)的 Android 设备上,从 Chrome 安装 PWA 会生成一个 WebAPK:Chrome 向 Google 服务器请求并安装的一个小型 APK,使应用获得启动器入口、Android 应用设置中的条目,以及覆盖其 scope 的 intent filter。没有 GMS 时,Chrome 只会添加一个带浏览器角标的主屏幕快捷方式;要上架 Google Play,则需把同一个 Web 应用封装为 Trusted Web Activity(TWA)。
安装形态取决于浏览器,而不是站点。在 Android 上,只有 GMS 设备上的 Chrome 与三星设备上的 Samsung Internet 会把 PWA 安装为 WebAPK;Firefox、Edge、Opera 以及无 GMS 设备上的 Chrome 添加的是在浏览器中打开站点的快捷方式(Making PWAs installable,MDN)。Android 版 Chrome 能运行的每个 Android 版本都支持安装,最早到 Jelly Bean。
- 图例
- 支持
- 部分支持
- 需开启标志
- 不支持
- 未知
| 浏览器 / 平台 | 支持 | 版本 | 置信度 | 来源 | 备注 |
|---|---|---|---|---|---|
| Chrome (Android) | 支持 | 57 | 中 | 来源 | 12 |
- 安装时通过 Google 的铸造服务器生成 WebAPK。
- 没有跨浏览器兼容性数据集(BCD / caniuse)收录 WebAPK;版本号依据 Chrome Platform Status 核对。
Trusted Web Activity 是另一套机制,有自己的数据集:
- 图例
- 支持
- 部分支持
- 需开启标志
- 不支持
- 未知
| 浏览器 / 平台 | 支持 | 版本 | 置信度 | 来源 | 备注 |
|---|---|---|---|---|---|
| Chrome (Android) | 支持 | 72 | 中 | 来源 | 123 |
- 依据 Chrome 文档,Trusted Web Activity 自 Android 版 Chrome 72 起可用。
- 没有跨浏览器兼容性数据集(BCD / caniuse)收录 TWA;版本号依据 Chrome 自己的文档核对。
- 同一份文档提到其他浏览器可能实现相同协议,但没有记录任何其他浏览器对 TWA 的支持。
Chrome 推广安装的前提
Section titled “Chrome 推广安装的前提”Chromium 系浏览器(Chrome、Samsung Internet、Edge)只在 manifest 具备以下成员时才主动推广安装:name 或 short_name;包含 192px 与 512px 两项的 icons;start_url;display 或 display_override;prefer_related_applications 为 false 或不存在。页面必须通过 https 提供,开发阶段可用 localhost 或 127.0.0.1;file:// 虽是安全上下文,但不算数。Service Worker 不是可安装性的必要条件。Android 版 Chrome、桌面版 Chrome、桌面版 Edge 与桌面版 Safari 还允许用户安装完全没有 manifest 的站点;manifest 的作用是让浏览器主动推广安装,并决定安装结果的形态。
Android 版 Chrome 面向用户的路径(英文界面)是三点 More 菜单,然后 Install and create shortcut,再 Install(Chrome 帮助)。页面也可以在 beforeinstallprompt 处理函数中自行打开同一个对话框,代码见「示例」。
WebAPK 带来什么
Section titled “WebAPK 带来什么”Chrome 根据 manifest 及其他元数据构建 WebAPK(WebAPKs on Android,web.dev)。安装之后:
- 应用在用户当初安装它的那个 Chrome 中打开,而不是 WebView。
- 它为
scope内的每个 URL 注册 intent filter。设置"scope": "/app/"后,点击指向/app/read/book的链接会打开应用,/help/则在浏览器标签页中打开。 - 权限不会在安装时授予。Android 会在安装时授予原生应用通知权限,但 WebAPK 必须在运行时通过 Chrome 自己的提示与设置申请。
- 存储就是浏览器 profile 的存储。Cookie、IndexedDB、Cache Storage 与 Service Worker 注册都与 Chrome 共享;清除 Chrome 的站点数据也会清掉已安装应用的数据。
- Chrome 71 及之后生成的 WebAPK 在 manifest 提供 512px 图标时,会在启动画面显示更大的图标。
- 生成的 APK 不被 Google Play 接受。要上架 Play 得用 TWA。
manifest 变更之后
Section titled “manifest 变更之后”Android 版 Chrome 在启动时,如果距上次检查超过 24 小时,会安排一次 manifest 拉取;拉取失败后间隔可能延长到 30 天(How Chrome handles updates to the web app manifest,web.dev)。name、short_name、icons、background_color、display、orientation、scope、shortcuts、start_url、theme_color 或 web_share_target 的变化会排队生成新的 WebAPK,Chrome 会等到所有应用窗口关闭、设备接通电源并连上 Wi-Fi 后才去请求。重命名或移动 manifest 文件可能让更新彻底停止;在 manifest 里存放用户专属值则会毫无收益地反复重建 APK。
面向 Google Play 的 Trusted Web Activity
Section titled “面向 Google Play 的 Trusted Web Activity”TWA 通过基于 Custom Tabs 的协议,从你发布的 Android 应用中打开你的源,Chrome 72 及之后可用(Trusted Web Activities,developer.chrome.com)。应用与站点必须通过 Digital Asset Links 建立关联;关联成立时,内容在用户的浏览器中全屏渲染,没有浏览器 UI。宿主应用无法直接访问 Cookie 或 localStorage,状态只能通过 URL(查询参数与 intent URI)传递。在低于 72 的 Chrome 上,同一个应用会回退为带普通工具栏的 Custom Tab。Bubblewrap 是生成 Android 工程的 Node.js CLI;打包步骤见 Trusted Web Activity(TWA):PWA 进入 Play 商店。
两个示例在浏览器标签页、WebAPK 与桌面应用窗口中都能原样运行,由特性检测决定用户看到什么。
展示自己的安装按钮
Section titled “展示自己的安装按钮”一旦 Chrome 判定页面可安装,beforeinstallprompt 就会在 window 上触发,通常在页面加载期间,但没有保证的时机。按钮要一直隐藏到事件到来,因为该事件只有 Chromium 系浏览器实现:
- 图例
- 支持
- 部分支持
- 需开启标志
- 不支持
- 未知
| 浏览器 / 平台 | 支持 | 版本 | 置信度 | 来源 | 备注 |
|---|---|---|---|---|---|
| Chrome (Android) | 支持 | 68 | 中 | 来源 | — |
| Chrome (Desktop) | 支持 | 73 | 中 | 来源 | — |
| Edge (Desktop) | 支持 | 79 | 中 | 来源 | — |
| Safari (iOS) | 不支持 | — | 中 | 来源 | 1 |
| Safari (macOS) | 不支持 | — | 中 | 来源 | 2 |
| Firefox (Desktop) | 不支持 | — | 中 | 来源 | 3 |
| Samsung Internet | 支持 | 9.0 | 中 | 来源 | — |
- 没有 beforeinstallprompt;需用户通过分享面板 → 添加到主屏幕手动安装。
- 通过「文件 → 添加到程序坞」菜单安装,而不是网页事件。
- 没有基于 manifest 的桌面安装路径。
<button id="install" hidden>安装</button>let installPrompt = null;const installButton = document.querySelector('#install');
window.addEventListener('beforeinstallprompt', (event) => { event.preventDefault(); // 压制 Chrome 自带的安装 UI installPrompt = event; // 保存事件供点击处理函数使用 installButton.removeAttribute('hidden');});
installButton.addEventListener('click', async () => { if (!installPrompt) return; const consumedPrompt = installPrompt; installButton.disabled = true; // 对话框打开期间禁止再次点击 try { const result = await consumedPrompt.prompt(); console.log(`安装提示结果:${result.outcome}`); // "accepted" 或 "dismissed" } finally { installPrompt = null; // 无论哪条退出路径,实例都已被消费 installButton.disabled = false; installButton.setAttribute('hidden', ''); }});prompt() 必须在用户激活的处理函数内运行,并且对同一个 BeforeInstallPromptEvent 实例只能调用一次(BeforeInstallPromptEvent: prompt() method,MDN),所以处理函数在 finally 中退役该事件,而不是只在成功后才这么做。iOS 上不存在这个事件,按钮会一直隐藏,用户从分享菜单安装。
读取实际生效的显示模式
Section titled “读取实际生效的显示模式”display-mode 报告的是浏览器实际应用的模式,当浏览器不支持所请求的值时,它会与 manifest 中的 display 不同(display-mode,MDN)。它描述的是呈现方式而非安装状态,因此只用它调整 UI,不要当成安装 API:
function applyDisplayMode(installButton) { if (!('matchMedia' in window)) { // matchMedia 不可用:让按钮保持隐藏,依赖浏览器菜单。 installButton.hidden = true; return; } if (window.matchMedia('(display-mode: standalone)').matches) { installButton.hidden = true; // 已经以应用窗口运行 }}匹配到 standalone 只说明页面不在普通标签页中,并不证明存在 WebAPK,因为桌面应用窗口与 iOS 主屏幕 Web 应用也会匹配同一个媒体查询。
WebAPK 的更新周期在设备上可以直接看到,这是区分「manifest 没更新」与「缓存问题」最快的办法。
卸载走的是 Android 而不是 Chrome:Settings > Apps > See all apps,点开该 Web 应用,再点 Uninstall(英文界面,Chrome 帮助)。开发者修改应用 name 后,Chrome 会向用户展示新名称,并提供 OK 接受或 Uninstall app 卸载;Chrome 帮助把模仿其他应用的改名视为开发者可能存在恶意的信号。
- WebAPKs on Android(web.dev)
- How Chrome handles updates to the web app manifest(web.dev)
- Trusted Web Activities(developer.chrome.com)
- 可安装性条件:PWA 如何才能被安装
- WebAPK:Chrome 在 Android 上安装 PWA 的方式
- Trusted Web Activity(TWA):PWA 进入 Play 商店
- 安装提示:beforeinstallprompt 与自定义安装
- 三星 Internet 浏览器上的 PWA
- 国内厂商浏览器
规范
| 规范 | 状态 |
|---|---|
| 无。 | |