检查用户是否已经在Chrome的主屏幕上安装了PWA?

Dav*_*les 19 javascript browser google-chrome homescreen progressive-web-apps

我正在尝试在渐进式Web应用程序上创建“添加到主屏幕”按钮,如Chrome文档中所述

我通常遵循规定的模式,其中有一些隐藏按钮,当Chrome beforeinstallprompt事件触发时会显示该按钮。触发事件后,我将捕获该事件,然后单击我自己的安装按钮后,使用该事件开始本机安装对话框。示例代码如下:

let deferredPrompt;

window.addEventListener('beforeinstallprompt', (e) => {
  // Prevent Chrome 67 and earlier from automatically showing the prompt
  e.preventDefault();
  // Stash the event so it can be triggered later.
  deferredPrompt = e;
  // Update UI notify the user they can add to home screen
  btnAdd.style.display = 'block';
});

btnAdd.addEventListener('click', (e) => {
  // hide our user interface that shows our A2HS button
  btnAdd.style.display = 'none';
  // Show the prompt
  deferredPrompt.prompt();
  // Wait for the user to respond to the prompt
  deferredPrompt.userChoice
    .then((choiceResult) => {
      if (choiceResult.outcome === 'accepted') {
        console.log('User accepted the A2HS prompt');
      } else {
        console.log('User dismissed the A2HS prompt');
      }
      deferredPrompt = null;
    });
});
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是,btnAdd如果用户已将Web应用程序安装到其主屏幕上,并且我想知道如何检查该情况,则不想显示我的安装按钮()。

我希望修改上面的代码如下:

window.addEventListener('beforeinstallprompt', (e) => {
  // Prevent Chrome 67 and earlier from automatically showing the prompt
  e.preventDefault();
  // Stash the event so it can be triggered later.
  deferredPrompt = e;

  // If the user has not already installed...
  deferredPrompt.userChoice
    .then(choiceResult => {
      if (choiceResult === undefined) {
        // Update UI notify the user they can add to home screen
        btnAdd.style.display = 'block';
      }
    });
});
Run Code Online (Sandbox Code Playgroud)

因此,如果用户已经安装,则不会显示安装按钮。但这似乎不起作用。看来,如果他们还没有做出选择,那么访问userChoice仅会通过本机对话直接提示用户。

我不太确定如何beforeinstallevent运作,因此这可能甚至不是一个好策略。理想情况下,我希望它可以像那样工作navigator.serviceWorker.ready(),它返回Promise而不是使用浏览器事件来尝试确定何时准备就绪。

无论如何,在显示自己的主屏幕安装按钮之前,如何确定用户是否已安装到主屏幕有任何想法?

编辑:正如Mathias所说,在显示按钮之前检查事件就足够了。我相信我遇到的问题是使用本地主机的结果,该主机beforeinstallprompt即使在安装后仍会不断触发该事件,这不是预期的行为。托管代码解决了该问题。

Mat*_*ias 18

也许在拦截自动弹出窗口之前不显示按钮?


在您的代码中,检查窗口是否为独立窗口;
如果为独立窗口,则无需显示按钮

if (window.matchMedia('(display-mode: standalone)').matches) {  
    // do things here  
    // set a variable to be used when calling something  
    // e.g. call Google Analytics to track standalone use   
}  
Run Code Online (Sandbox Code Playgroud)

我的示例测试器在这里
https://a2hs.glitch.me

我的测试人员的源代码
https://github.com/ng-chicago/AddToHomeScreen

  • 在显示弹出窗口之前,我已经在检查事件,但我相信这是正确的解决方案。看我上面的评论。检查独立模式绝对是一个方便的技巧,但这意味着安装按钮仍会显示在安装后的浏览器视图(非独立)中。 (2认同)
  • 此代码检测网站是否作为应用程序启动 - 例如,它不会检测用户是否安装了应用程序但正在从浏览器查看网站。 (2认同)
  • @AlexWalker 正确。浏览器中的网页无权查看设备上安装的应用程序。在大多数情况下,从已安装的 Icon 安装 PWA 的用户将使用该图标而不是 URL。所以这不是一个经常发生的问题(我认为) (2认同)

DLe*_*jak 16

回答原来的问题。使用最新版本的 Chrome,您可以使用window.navigator.getInstalledRelatedApps(). 它返回一个承诺,其中包含您的 Web 应用程序在 manifest.json 中指定为相关的已安装应用程序数组。要启用此功能,您需要将related_applications字段添加到 manifest.json

  "related_applications": [{
    "platform": "webapp",
    "url": "https://app.example.com/manifest.json"
  }]
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

//check if browser version supports the api
if ('getInstalledRelatedApps' in window.navigator) {
  const relatedApps = await navigator.getInstalledRelatedApps();
  relatedApps.forEach((app) => {
    //if your PWA exists in the array it is installed
    console.log(app.platform, app.url);
  });
}
Run Code Online (Sandbox Code Playgroud)

来源:API 文档

现在,您可以根据是否安装了应用程序来显示一些元素。例如:您可以显示“打开应用程序”按钮并将用户重定向到 PWA。但请记住,当用户已经在使用@Mathias 的回答并检查应用程序中时禁用它(display-mode: standalone)

但是,关于您的用例。您应该仅在beforeinstallprompt被拦截时显示安装按钮。如果设备上已安装 PWA,浏览器不会触发此事件。当提示被触发并choiceResult.outcome === 'accepted'再次隐藏按钮时。

  • 页面上注明它适用于_**Android**:Chrome 84 或更高版本_。因此,尽管模仿移动设备,您的**桌面** Chrome 可能并不支持它。 (2认同)

San*_*mar 8

这是一个简单的函数,告诉您该应用程序是在浏览器中还是在 PWA 中打开。原始来源链接

function getPWADisplayMode() {
  const isStandalone = window.matchMedia('(display-mode: standalone)').matches;
  if (document.referrer.startsWith('android-app://')) {
    return 'twa';
  } else if (navigator.standalone || isStandalone) {
    return 'standalone';
  }
  return 'browser';
}
Run Code Online (Sandbox Code Playgroud)


Bor*_*ski 5

我看不出这是正确的答案,因为这基本上是检查用户是否已经使用该应用程序,但我们不希望的行为是“当用户在网络上并尝试再次安装该应用程序时告诉他已经在他的设备中安装了该应用程序”。在我看来,这不是解决这个问题的答案。

我们可以做的是: 1. 当用户点击安装但他的设备上有应用程序时,在这种情况下,beforeinstallprompt事件不会被触发,因此该事件将返回空值。我们将结果存储在全局变量中,当结果为空时,我们向用户显示他已经安装了该应用程序。2.当用户点击安装,但没有自己的设备上的应用。在这种情况下,beforeinstallprompt事件将被解雇所以这个事件将返回访问显示提示。我们可以将结果存储在全局变量中,如果它不是 NULL(不会是),因为beforeinstallprompt如果用户在他的设备上没有应用程序会被触发,我们会向用户显示 prompt()。

我怀疑我的解决方案是否也很好,但我认为问题和正确答案没有任何共同点

window.addEventListener("beforeinstallprompt", event => {
  window.deferedPrompt = event;
});

handleButtonClick = () => {
 const promptEvent = window.deferedPrompt;
 if(!promptEvent){
 // DO SOMETHING
 }
//Show the add to home screen prompt
promptEvent.prompt()

promptEvent.userChoice.then((result: any) => {
      // Reset the deferred prompt variable, since
      // prompt() can only be called once.
      window.deferedPrompt = null;.
    });
}



<button onClick={handleButtonClick}>Install</button>
Run Code Online (Sandbox Code Playgroud)