I\'m trying to create an \"Add To Home Screen\" button on my progressive web app, as described in Chrome\'s documentation.
I\'m generally following the prescribed p
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
Source code for my tester
https://github.com/ng-chicago/AddToHomeScreen
I was looking for something similar and the simple solution is the scope passed in the manifest.web
manifest file (manifest.json
renamed to manifest.webm
),
we need to remove the scope from the manifest file and now if we have PWA added to our home screen and someone clicks a link outside the PWA triggers open by default.
Website : https://ctrltab.co.in/
manifest: https://ctrltab.co.in/manifest.webmanifest
<!-- start with hidden button -->
<button id="install" style="display:none;">install</button>
// 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!");
});
To answer original question. With latest versions of Chrome you can use window.navigator.getInstalledRelatedApps()
. It returns a promise with an array of installed apps that your web app specifies as related in the manifest.json. To enable this to work you need to add related_applications
field to manifest.json
"related_applications": [{
"platform": "webapp",
"url": "https://app.example.com/manifest.json"
}]
And then you can use it like:
//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);
});
}
Source: API docs
Now you can display some elements depending if your app is installed. E.g: you can display "Open app" button and redirect user to PWA. But remember to disable it when the user is already in the app using @Mathias's answer and checking (display-mode: standalone)
However, regarding your use case. You should display install button only when beforeinstallprompt
is intercepted. Browser does not fire this event if the PWA is already installed on the device. And when prompt is fired and choiceResult.outcome === 'accepted'
you hide the button again.
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 beforeinstallprompt
event WON'T BE fired 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 beforeinstallprompt
event WILL be fired 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 beforeinstallprompt
will be fired if the user don't have the app on his device we show the prompt() to the user.
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>