javascript 检查用户是否已经在 Chrome 上将 PWA 安装到主屏幕?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/51735869/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
check if user has already installed PWA to homescreen on Chrome?
提问by David Scales
I'm trying to create an "Add To Home Screen" button on my progressive web app, as described in Chrome's documentation.
我正在尝试在我的渐进式网络应用程序上创建一个“添加到主屏幕”按钮,如Chrome 文档中所述。
I'm generally following the prescribed pattern, where I have some hidden button which is displayed when Chrome's beforeinstallpromptevent fires.
I capture the event once it fires, and then use the event to begin the native install dialogue once my own install button is clicked. The sample code is below:
我通常遵循规定的模式,其中有一些隐藏按钮,当 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;
});
});
The issue I'm running into is that I don't want to show my install button (btnAdd) if the user has already installed the web app to thier home screen, and I'm having trouble figuring out how to check for that scenario.
我遇到的问题是,btnAdd如果用户已经将 Web 应用程序安装到其主屏幕,我不想显示我的安装按钮 ( ),并且我无法弄清楚如何检查该场景。
I was hoping to modify the above code as follows:
我希望修改上面的代码如下:
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';
}
});
});
So that the install button won't be displayed if the user has already installed. But this doesn't seem to work. It appears that if they haven't made a choice already, accessing userChoicejust prompts the user directly with the native dialogue.
如果用户已经安装,则不会显示安装按钮。但这似乎不起作用。看起来,如果他们还没有做出选择,访问userChoice只会直接用原生对话提示用户。
I'm not really sure how the beforeinstalleventworks, so this might not even be a good strategy. Ideally I was hoping this would work something like something like navigator.serviceWorker.ready(), which returns a Promise rather than using browser events to try and figure out when stuff is ready.
我不确定它是如何beforeinstallevent工作的,所以这甚至可能不是一个好的策略。理想情况下,我希望这会像 那样工作navigator.serviceWorker.ready(),它返回一个 Promise 而不是使用浏览器事件来尝试确定什么时候东西准备好了。
In any case, are there any ideas on how I can check that the user has installed to home screen before I show my own home screen install button?
无论如何,在显示我自己的主屏幕安装按钮之前,是否有关于如何检查用户是否已安装到主屏幕的任何想法?
Edit:As Mathias has commented, checking for the event before showing the button should be sufficient. I believe the issue I was having is a result of using localhost, which appears to continually fire the beforeinstallpromptevent even after installation, which is not the intended behavior. Hosting the code solved the issue.
编辑:正如 Mathias 所评论的,在显示按钮之前检查事件应该就足够了。我相信我遇到的问题是使用 localhost 的结果,beforeinstallprompt即使在安装后它似乎也会持续触发事件,这不是预期的行为。托管代码解决了这个问题。
回答by Mathias
Perhaps, don't show the button until you intercept the automatic pop-up?
也许,在您拦截自动弹出窗口之前不要显示按钮?
or
In your code, check to see if the window is standalone
If it is, you need not show the button
或
在您的代码中,检查窗口是否是独立的,
如果是,则不需要显示按钮
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
}
My example tester here
https://a2hs.glitch.me
我的示例测试人员在这里
https://a2hs.glitch.me
Source code for my tester
https://github.com/ng-chicago/AddToHomeScreen
回答by Leonardo Filipe
HTML
HTML
<!-- start with hidden button -->
<button id="install" style="display:none;">install</button>
JAVASCRIPT
爪哇脚本
// variable store event
window.deferredPrompt = {};
// get button with id
const install_button = document.querySelector('#install');
// if the app can be installed emit beforeinstallprompt
window.addEventListener('beforeinstallprompt', e => {
// this event does not fire if the application is already installed
// then your button still hidden ;)
// show button with display:block;
install_button.style.display = 'block';
// prevent default event
e.preventDefault();
// store install avaliable event
window.deferredPrompt = e;
// wait for click install button by user
install_button.addEventListener('click', e => {
window.deferredPrompt.prompt();
window.deferredPrompt.userChoice.then(choiceResult => {
if (choiceResult.outcome === 'accepted') {
// user accept the prompt
// lets hidden button
install_button.style.display = 'none';
} else {
console.log('User dismissed the prompt');
}
window.deferredPrompt = null;
});
});
});
// if are standalone android OR safari
if (window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone === true) {
// hidden the button
install_button.style.display = 'none';
}
// do action when finished install
window.addEventListener('appinstalled', e => {
console.log("success app install!");
});
回答by BorisDedejski
I don't see how this is the correct answer, because this is basically a check if user uses the App already, but the behavior we wan't is "When the user is on the web and tries to install the app again to tell him that he already has the app in his device". Upon me this is not an answer that solves this.
我看不出这是正确的答案,因为这基本上是检查用户是否已经使用该应用程序,但我们不希望的行为是“当用户在网络上并尝试再次安装该应用程序时告诉他已经在他的设备中安装了该应用程序”。在我看来,这不是解决这个问题的答案。
What we can do is:
1. When the user clicks install but has the application on his device
In this case the beforeinstallpromptevent WON'T BEfired so this event will return null. We store the result in global variable and when the result is null we show this to user that he already has the app installed.
2. When the user clicks install but doesn't have the application on his device
In this case the beforeinstallpromptevent WILL befired so this event will return access to show the prompt.
We can store the result in global variable and if it is not NULL (which won't be) because beforeinstallpromptwill be fired if the user don't have the app on his device we show the prompt() to the user.
我们可以做的是: 1. 当用户点击安装但在他的设备上有应用程序时,在这种情况下,beforeinstallprompt事件不会被触发,因此该事件将返回空值。我们将结果存储在全局变量中,当结果为空时,我们向用户显示他已经安装了该应用程序。2.当用户点击安装,但没有自己的设备上的应用。在这种情况下,beforeinstallprompt事件将被解雇所以这个事件将返回访问显示提示。我们可以将结果存储在全局变量中,如果它不是 NULL(不会是),因为beforeinstallprompt如果用户在他的设备上没有应用程序会被触发,我们会向用户显示 prompt()。
I doubt if mine solution is good too but I think that the Question and the correct answer don't have nothing in common
我怀疑我的解决方案是否也很好,但我认为问题和正确答案没有任何共同点
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>

