跳转到内容

安装 · API

beforeinstallprompt 事件

发布于 更新于

有限可用不支持的浏览器: Safari (iOS)、Safari (macOS)、Firefox (Desktop)WICG 草案

beforeinstallprompt 是 Chromium 浏览器在页面满足可安装性条件后于 window 上触发的事件;处理器调用 preventDefault() 压住浏览器自己的横幅,保存这个 BeforeInstallPromptEvent,之后在点击中调用 prompt(),让安装对话框在页面选定的时机打开。Android 上的 Chrome 68、桌面端 Chrome 73、Edge 79 与 Samsung Internet 9.0 会触发它;Safari(iOS 与 macOS)与 Firefox 从不触发,只能从各自的菜单安装(BCD api.BeforeInstallPromptEvent)。

安装提示流程图:站点满足可安装性条件后,Chromium 浏览器触发 beforeinstallprompt;页面调用 preventDefault()、保存事件并显示自己的安装按钮;在用户手势中调用 prompt(),浏览器弹出安装对话框,userChoice 兑现为 accepted(随后触发 appinstalled)或 dismissed;Safari 与 Firefox 不触发该事件,而是通过浏览器菜单安装。
从可安装性条件到 appinstalled:Chromium 浏览器中的 beforeinstallprompt 流程。
window.addEventListener('beforeinstallprompt', (event) => {
event.preventDefault(); // 先不让浏览器显示自己的横幅
deferred = event; // 一次性:只能用于一次 prompt()
});
const { outcome, platform } = await deferred.prompt(); // 必须在用户手势中
// 或:const { outcome, platform } = await deferred.userChoice;
window.addEventListener('appinstalled', () => { /* 从任何界面完成的安装 */ });

prompt() 返回的 Promise 与 userChoice 兑现为同一个 { outcome, platform } 对象,二者 await 哪个都可以。无论安装来自 prompt()、地址栏图标还是浏览器菜单,appinstalled 都会在 window 上触发。

BeforeInstallPromptEvent 在 Event 之上扩展了两个成员;appinstalled 是普通的 Event。

成员 类型 说明
platforms readonly string[] 浏览器提供的安装目标,例如桌面端为 ["web"],Android 上当 manifest 列出 Play 应用且设置 prefer_related_applications 时为 ["web", "play"]。
userChoice Promise<{ outcome, platform }> 对话框关闭后兑现。outcome 为 "accepted" 或 "dismissed";platform 是 platforms 中被选中的项,取消时为 ""。
prompt() Promise<{ outcome, platform }> 显示浏览器的安装对话框。每个事件只允许调用一次,且必须有瞬时用户激活。
preventDefault() 继承 阻止浏览器在这次可安装性检查中显示自己的安装横幅(Android 上的 mini-infobar)。

页面必须通过 HTTPS(或 localhost)提供,并链接一个带有 name 或 short_name、start_url、非 browser 的 display、以及包含 192 px 与 512 px 尺寸图标的 manifest。Chrome 在 Android 上自 Chrome 108、桌面端自 Chrome 112 起取消了从浏览器菜单安装时的 service worker 要求,并提供默认离线页;Chrome 团队关于这次调整的文章指出,beforeinstallprompt 背后的启发式仍然检查 fetch 处理器,因此没有 service worker 的页面可能可以从菜单安装,却始终收不到该事件。应用已安装期间,以及参与度启发式尚未满足时,Chrome 也不会触发它。

只有 prompt() 会拒绝;该 API 中没有别的会抛出。

  • NotAllowedError:在没有瞬时用户激活的情况下调用了 prompt(),例如在页面加载时或定时器中。Chromium 的报错信息为 The prompt() method must be called with a user gesture。
  • InvalidStateError:对同一个事件第二次调用 prompt(),或事件底层的横幅请求已失效(页面已导航,或浏览器已经显示过自己的界面)。

Safari 与 Firefox 中事件从不触发,所以不存在可被误用的事件对象;假定提示一定会来的代码只是永远不会显示它的按钮。

两个示例都运行在页面中;假定 service worker 与 manifest 已经就位。

处理器保存事件并显示按钮。点击处理器调用 prompt()、读取结果,并清空保存的事件,因为它不能复用。appinstalled 监听器负责在用户从浏览器自带界面安装时隐藏按钮。

let deferred = null;
const button = document.querySelector('#install');
window.addEventListener('beforeinstallprompt', (event) => {
event.preventDefault();
deferred = event;
button.hidden = false;
});
button.addEventListener('click', async () => {
if (!deferred) return;
const { outcome, platform } = await deferred.prompt();
deferred = null; // 事件只能用一次
button.hidden = true;
if (outcome === 'accepted') analytics.track('install_accepted', { platform });
});
window.addEventListener('appinstalled', () => {
deferred = null;
button.hidden = true;
});

一次取消的代价不止是丢掉一次点击:Chrome 会对同一站点施加自己的冷却期,之后才再次触发 beforeinstallprompt,所以把按钮放在用户完成一项任务之后、而不是首屏,能让页面拿到的这唯一一次事件用在更可能被接受的时刻。

检测支持,并为 Safari 用户改为给出指引

Section titled “检测支持,并为 Safari 用户改为给出指引”

Safari 从不触发该事件。页面仍可以检测自己是否已以安装态运行(display-mode: standalone,或 iOS 上的旧属性 navigator.standalone),若没有,就用分享菜单的说明代替一个永远不会出现的按钮。

const installed =
window.matchMedia('(display-mode: standalone)').matches ||
navigator.standalone === true; // 仅 iOS Safari
const supportsPrompt = 'onbeforeinstallprompt' in window;
if (installed) {
hideAllInstallUi();
} else if (!supportsPrompt) {
// Safari 与 Firefox:不会有事件到来。说明手动路径。
showHint(/iPhone|iPad/.test(navigator.userAgent)
? '点按"共享",然后选择"添加到主屏幕"。'
: '请使用浏览器菜单安装此应用。');
}
// Chromium:等 beforeinstallprompt 触发后再显示任何东西。

在所有实现了该事件的 Chromium 浏览器中 'onbeforeinstallprompt' in window 都为 true,所以指引分支只在无法等待事件的地方运行;Chromium 分支则把安装界面一直隐藏到事件确认可安装为止。

规范

规范状态
安装提示(beforeinstallprompt)WICG 草案
  • 图例
  • 支持
  • 部分支持
  • 需开启标志
  • 不支持
  • 未知
浏览器 / 平台支持版本置信度来源备注
Chrome (Android)支持68中来源—
Chrome (Desktop)支持73中来源—
Edge (Desktop)支持79中来源—
Safari (iOS)不支持—中来源1
Safari (macOS)不支持—中来源2
Firefox (Desktop)不支持—中来源3
Samsung Internet支持9.0中来源—
  1. 没有 beforeinstallprompt;需用户通过分享面板 → 添加到主屏幕手动安装。
  2. 通过「文件 → 添加到程序坞」菜单安装,而不是网页事件。
  3. 没有基于 manifest 的桌面安装路径。

源数据: /compatibility/install-prompt.json · 全球使用占比: 72 % (StatCounter 2026-05)

来源: 规范 · MDN · 最近核验 2026-06-24 · 置信度: 中 (由来源计算)