从 PWA 触发安装

警告:此处描述的技术依赖于 beforeinstallprompt 事件,该事件不是标准事件,目前仅在基于 Chromium 的浏览器中实现。

默认情况下,如果用户访问您的网站,并且浏览器确定该网站 可以作为 PWA 安装,那么浏览器将显示一些内置 UI — 例如,URL 栏中的图标 — 来安装该网站。如果用户单击该图标,则浏览器会显示一个安装提示,其中至少包含应用的 名称图标。如果用户同意安装该应用,则会进行安装。

但是,您可以实现自己的应用内 UI 来询问用户是否要安装该应用,这将触发安装提示。这样做的优点是:

  • 您可以提供有关应用的更多上下文信息,向用户解释他们为什么可能想要将其安装为 PWA。
  • 应用内安装 UI 可能比浏览器默认 UI 更容易被用户发现和理解。

添加应用内安装 UI

首先,在应用中添加一些 UI,表明用户可以安装它。例如:

html
<button id="install" hidden>Install</button>

我们设置了按钮的 hidden 属性,因为如果用户使用无法安装该应用的浏览器访问应用,我们不希望显示安装 UI。接下来,我们将看到如何仅在支持本地安装 PWA 的浏览器中显示按钮。

监听 beforeinstallprompt

一旦浏览器确定它可以安装该应用,它就会在全局 Window 范围中触发 beforeinstallprompt 事件。

在我们的主应用代码中,我们将监听此事件:

js
// main.js

let installPrompt = null;
const installButton = document.querySelector("#install");

window.addEventListener("beforeinstallprompt", (event) => {
  event.preventDefault();
  installPrompt = event;
  installButton.removeAttribute("hidden");
});

这里的事件处理程序执行三项操作:

  • 在事件上调用 preventDefault()。这可以阻止浏览器显示自己的安装 UI。
  • 获取传递到处理程序的事件对象的引用。这是一个 BeforeInstallPromptEvent 实例,它将使我们能够提示用户安装应用。
  • 通过删除按钮上的 hidden 属性来显示我们的应用内安装 UI。

请注意,当以下情况发生时,事件不会触发:

  • PWA 已安装。
  • 应用不符合 PWA 安装标准
  • 当前设备不支持安装 PWA(例如,由于缺少权限)。

触发安装提示

接下来,我们需要为我们的应用内安装按钮添加一个点击事件处理程序:

js
// main.js

installButton.addEventListener("click", async () => {
  if (!installPrompt) {
    return;
  }
  const result = await installPrompt.prompt();
  console.log(`Install prompt was: ${result.outcome}`);
  disableInAppInstallPrompt();
});

function disableInAppInstallPrompt() {
  installPrompt = null;
  installButton.setAttribute("hidden", "");
}

installPrompt 变量是在我们的 beforeinstallprompt 事件处理程序中与 BeforeInstallPromptEvent 对象一起初始化的。如果 installPrompt 由于任何原因未初始化,我们则不做任何操作。

否则,我们调用其 prompt() 方法。这将显示安装提示,并返回一个 Promise,该 Promise 会解析为一个对象,指示应用是否已安装。特别是,如果用户选择安装该应用,其 outcome 属性为 "accepted";如果他们关闭了提示,则为 "dismissed"

无论哪种情况,我们都必须在调用 prompt() 后重置我们的状态,因为我们只能为每个 BeforeInstallPromptEvent 实例调用一次。因此,我们重置 installPrompt 变量并再次隐藏安装按钮。

响应应用安装

根据浏览器和平台的不同,浏览器可能仍会提供自己的 UI 来安装应用。这意味着应用仍可能在不经过我们的应用内安装 UI 的情况下进行安装。如果发生这种情况,我们希望禁用应用内安装 UI,否则将在已安装的应用中显示它。

为此,我们可以监听 appinstalled 事件,该事件在应用安装后会在全局 Window 范围内触发。

js
// main.js

window.addEventListener("appinstalled", () => {
  disableInAppInstallPrompt();
});

function disableInAppInstallPrompt() {
  installPrompt = null;
  installButton.setAttribute("hidden", "");
}

响应已安装的平台特定应用

如果您有平台的特定版本应用以及 Web 应用,并且您想根据平台特定应用是否已安装来个性化 Web 应用体验。如果用户已安装平台特定应用,您可能不想邀请他们安装 PWA,并且/或者您可能希望他们前往平台特定应用查看内容。

这可以通过 Navigator.getInstalledRelatedApps() 方法来处理,该方法允许您检测已安装的相关平台特定应用(或 PWA)并做出相应响应。

例如

js
const relatedApps = await navigator.getInstalledRelatedApps();

// Search for a specific installed platform-specific app
const psApp = relatedApps.find((app) => app.id === "com.example.myapp");

if (psApp) {
  // Update UI as appropriate
}

此方法还可以与 beforeinstallprompt 结合使用,以根据平台特定应用的可用性来抑制浏览器的安装 UI。

js
window.addEventListener("beforeinstallprompt", async (event) => {
  const relatedApps = await navigator.getInstalledRelatedApps();

  // Search for a specific installed platform-specific app
  const psApp = relatedApps.find((app) => app.id === "com.example.myapp");

  if (psApp) {
    event.preventDefault();
    // Update UI as appropriate
  }
});

另见