← 返回博客
Illustration of an Android phone home screen with a web app install banner showing a home icon and download arrow

Chrome 安装提示优化:触发时机、自定义安装按钮与提示不出现的排查顺序(2026)

Chrome 安装提示优化包含三件事:先让页面通过 Chrome 的可安装性检查,beforeinstallprompt 事件才会触发;然后捕获这个事件,用你自己的安装按钮在合适的时机替代 Chrome 默认的底部小横幅;最后把按钮文案和位置写好,给访客一个点下去的理由。下面逐层讲清楚每一部分怎么工作、哪些设置决定提示会不会出现,以及提示不出现时的排查顺序。

你优化的到底是什么

安卓上的 Chrome 不会因为你想弹安装提示就弹。只有当页面满足可安装性条件、访客又表现出一定互动之后,Chrome 才会触发 beforeinstallprompt 事件,这时你的代码才能调用 prompt() 弹出原生对话框。你能影响的东西分三层:

  1. 可安装性:manifest、HTTPS、service worker,以及尚未安装这一条。这层不过,后面全白搭。
  2. 触发时机:相对于访客刚做了什么,你在什么时候调用 prompt()。
  3. 呈现方式:你展示的自定义按钮或横幅、文案、位置,以及访客接受或关闭之后发生什么。

如果你需要先了解平台背景,比如安卓和 iOS 的提示机制有什么不同、各自会发生什么,可以看我们关于添加到主屏幕提示的文章。本文只讲 Chrome 这条路怎么调。

Chrome 安装提示优化从可安装性开始

Chrome 的可安装性条件在 web.dev 和 Chrome for Developers 上有文档,它是第一道闸。按当前 Chrome 版本,清单是:

  • 通过 HTTPS 提供(开发时 localhost 例外)。
  • 页面链接了一个 Web 应用 manifest,至少包含:name 或 short_name、start_url、display 设为 standalone、fullscreen 或 minimal-ui(或 display_override 里含其中之一),以及 icons 里包含 192 乘 192 和 512 乘 512 的 PNG。
  • prefer_related_applications 不存在或为 false。它为 true 时,Chrome 会把用户引导到 related_applications 里列出的原生应用。
  • 该应用尚未安装在这台设备上。
  • 用户互动启发式:访客在这个域名上停留了一小段时间并至少点击过一次页面。Chrome 不公布具体数字,而且会变,但首次加载、零互动时什么都不触发,是设计如此。

有两条旧教程还在列的要求已经放宽。Chrome 几个版本前取消了离线可用这条检查,后来又放宽了 service worker 对可安装性的要求。实践中你仍然应该注册 service worker:安卓上的旧版 Chrome 还会检查它,其他 Chromium 内核浏览器可能不同,而且 service worker 是安装后的应用能快速启动、在弱网下不白屏的基础。

一个能通过检查的最小 manifest:

{
  "name": "Example App",
  "short_name": "Example",
  "start_url": "/?source=pwa",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#0a84ff",
  "icons": [
    { "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" }
  ]
}

如果希望启动器图标填满安卓的自适应形状,而不是缩在一个白圆圈里,再加一条单独的 maskable 图标。这是主屏幕上肉眼可见的质量信号,直接决定安装后的图标看起来像不像一个真正的应用。

捕获 beforeinstallprompt,做自定义安装按钮

安卓 Chrome 的默认行为是在条件满足后,在底部弹一个小横幅(mini-infobar)。它很容易被忽略、也很容易被划掉,而且一旦划掉,Chrome 会等很久才再次显示。自定义安装按钮的全部意义,就是把这个时刻的控制权拿回来。

let deferredPrompt = null;
const installButton = document.getElementById('install-btn');

window.addEventListener('beforeinstallprompt', (event) => {
  // 阻止 Chrome 立刻显示底部小横幅
  event.preventDefault();
  deferredPrompt = event;
  // 事件证明可安装之后,再显示你自己的按钮
  installButton.hidden = false;
});

installButton.addEventListener('click', async () => {
  if (!deferredPrompt) return;
  deferredPrompt.prompt();
  const { outcome } = await deferredPrompt.userChoice; // 'accepted' | 'dismissed'
  // 被延迟的事件只能用一次
  deferredPrompt = null;
  installButton.hidden = true;
  // 在这里把 outcome 发给统计
});

window.addEventListener('appinstalled', () => {
  // 从任何入口安装成功后都会触发,包括 Chrome 自己的菜单
  deferredPrompt = null;
  installButton.hidden = true;
});

由事件设计推出来的几条规则:

  • prompt() 必须在用户手势(点你的按钮)里调用。放在定时器或页面加载里调用会被忽略。
  • 每个 beforeinstallprompt 事件只能支撑一次 prompt() 调用。访客关闭后不能立刻再调,要等新事件,而 Chrome 一段时间内不会再触发。
  • 事件到来之前安装按钮要保持隐藏。一个点了没反应的按钮(因为事件根本没触发)比没有按钮更糟。
  • 监听 appinstalled 来清理界面并记录转化。userChoice 的结果告诉你访客点了安装,appinstalled 告诉你安装完成了。

触发时机:什么时候显示按钮

事件只说明可以安装,不代表访客准备好了。Chrome 在 web.dev 上的建议是等访客有了想要这个应用的理由之后再推广安装,我们在安装类投放上的经验也指向同一个方向。有效的模式:

  • 完成一个动作之后:访客读完了内容、提交了表单、加了东西、走到了流程结尾。在确认状态上显示安装按钮。
  • 再次访问时:同一域名的第二次会话比第一次是更强的兴趣信号。用 localStorage 计数,在第二或第三次访问时推广。
  • 内容页按滚动深度或停留时长:访客滚过首屏并停留一会儿之后再显示,而不是第一秒就显示。
  • 当安装本身就是 offer,比如落地页的目的就是把应用装到主屏幕,那就把按钮放在首屏当主行动按钮,但仍然要等事件触发之后才显示。在那之前隐藏它,或者显示一个带一句简短说明的不可用状态。

有害的模式:在 setTimeout 里调 prompt()(会静默失败并消耗掉手势);在访客还没看到任何内容之前就用安装横幅盖住页面;被关闭之后每个页面都再弹一次。关闭是一种信息,按你自己定的周期尊重它(存一个时间戳,几天或几周内不再推广)。

安装按钮的文案与位置

Chrome 的原生对话框显示你的应用名、图标和一个安装按钮,那段文字你改不了。你能控制的是访客点下去走到那一步的元素,以及它周围的文字。

  • 按钮写收益而不是机制:加到主屏幕一键打开、安装后加载更快且离线可用,都比安装 PWA 好。多数访客不知道这个缩写是什么。
  • 说清楚代价:不用去商店下载、不需要注册账号、可以像任何应用一样删除。常见的犹豫是觉得安装意味着一个很大的下载包。
  • 把按钮放在自然会点的位置:安装优先的落地页放首屏,文章页放内容末尾,回访用户放页头。避免和浏览器自己的底栏抢位置的悬浮层。
  • 在按钮旁边放应用图标。它预告了主屏幕上会出现什么,也和接下来的原生对话框对得上。
  • 一屏只放一个安装提示。把它和通知权限请求、订阅弹窗放在同一时刻,会把三者的接受率一起拉低。

对安装优先的页面来说,落地页本身就是提示的环境,按钮周围的页面结构怎么搭,见我们的PWA 落地页指南。

Chrome 安装提示不出现:排查顺序

beforeinstallprompt 一直不触发时,按下面的顺序查。Chrome DevTools 的 Application 面板下的 Manifest 页会逐条列出可安装性错误,多数问题在那里就有答案。

  1. 打开 DevTools,Application,Manifest,看可安装性部分。缺图标尺寸、display 值不对、start_url 跳到别的域名或返回非 200 状态、manifest 解析错误,都会显示在这里。
  2. 确认访客实际落到的那个 URL 是 HTTPS,包括广告点击之后的所有跳转。
  3. 检查应用是否已经安装。已安装的应用 Chrome 不会再触发事件。用新的浏览器配置测,或者先卸载。安卓上 Chrome 的 chrome://webapks 页面列出了已安装的 Web 应用。
  4. 检查是否最近被关闭过。如果测试人员之前在同一设备上划掉了提示,Chrome 会在一段冷却期内压制它,web.dev 对 mini-infobar 的描述是大约三个月。测试请用全新的配置。
  5. 检查浏览器。beforeinstallprompt 是 Chromium 的特性,Safari 里没有,Firefox 里不触发,在 Facebook、Instagram、TikTok 和大多数应用的内嵌浏览器里也不触发,因为那些是 WebView,不是 Chrome。对广告流量来说这通常才是真正的原因:访客在应用的浏览器里,事件永远不会触发,安装按钮永远不会出现。修法在落地页而不在 manifest:识别应用内浏览器,先把访客引到 Chrome,再推广安装。
  6. 检查 prefer_related_applications。它为 true 且列了关联的原生应用时,Chrome 会推广那个应用。
  7. 检查互动启发式。先和页面互动(点一下、停几秒)再期待事件。
  8. 检查你自己的代码。调了 preventDefault() 却从未调用 prompt(),提示就被截住再也不用了;监听器在事件已经触发之后才挂上,也会错过。监听器要尽早在页面加载时挂上。
  9. 在 Application,Service Workers 里检查 service worker。即使它已经不是硬性要求,旧版 Chrome 上一个注册失败的 service worker 仍会挡住提示。

九条都过、在安卓上干净的 Chrome 配置里事件仍不触发,先记下 Chrome 版本并用 Chrome 自己的可安装性工具测一遍,再怀疑页面。

怎么衡量优化有没有效果

把提示当成四步漏斗,每一步都记录:

  • beforeinstallprompt 触发(这位访客通过了可安装性)。
  • 安装按钮显示(你的时机规则触发了)。
  • prompt() 被调用(访客点了你的按钮)。
  • userChoice 为接受且 appinstalled 触发。

第一步和最后一步之间的比值告诉你弱点在页面、时机还是文案;按流量来源对比,能看出差距里有多少是应用内浏览器的问题。这些事件怎么发到 GA4、怎么归因到投放,见我们关于衡量添加到主屏幕转化的文章。

ROIBest 的 PWA 落地页就是围绕这条序列为广告流量搭建的:从应用内浏览器切换到 Chrome,自定义安装按钮绑定 beforeinstallprompt,安装事件按漏斗分步记录,你可以看到访客在哪一步流失。

常见问题

为什么我的网站上 beforeinstallprompt 不触发?

最常见的是四种原因之一:manifest 没通过可安装性检查(看 DevTools 的 Application,Manifest)、应用已经安装、提示最近被关闭过而 Chrome 处于冷却期、页面是在非 Chrome 浏览器里打开的,比如根本没有这个事件的应用内 WebView。

能不能在页面加载时自动弹出 Chrome 安装提示?

不能。prompt() 只能在点击这类用户手势里调用,而且要等 beforeinstallprompt 触发之后。事件到来后你可以自动显示自己的安装按钮,但原生对话框需要访客点一下。

安装提示可以显示几次?

每个 beforeinstallprompt 事件一次。被关闭之后 Chrome 会等一段时间才再次触发事件,你自己也应该把关闭记录下来,几天或几周内不再推广,而不是每个页面都弹。

安装提示在 Facebook 或 TikTok 的应用内浏览器里能用吗?

不能。这些应用用内嵌的 WebView 打开页面,WebView 没有实现 beforeinstallprompt。对广告流量,先识别应用内浏览器,引导访客在 Chrome 里打开页面,再显示安装按钮。

ROIBest

用 ROIBest 打造下一阶段增长引擎

联系我们,获取稳定、高转化的安卓 PWA 解决方案。