Fix PWA redirect loop and installation options after uninstalling PWA
This commit is contained in:
+183
-30
@@ -26,6 +26,9 @@ export class AppComponent implements OnInit {
|
||||
|
||||
public showRedirectOverlay = signal<boolean>(false);
|
||||
public showInstallOverlay = signal<boolean>(false);
|
||||
public isInstalling = signal<boolean>(false);
|
||||
public isRedirecting = signal<boolean>(false);
|
||||
public isPwaInstalled = signal<boolean>(false);
|
||||
public redirectFailed = signal<boolean>(false);
|
||||
public protocolLink = '';
|
||||
|
||||
@@ -45,13 +48,12 @@ export class AppComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
|
||||
// Se l'overlay di redirect o di installazione è mostrato, NON nascondiamo il loader iniziale
|
||||
// per rimanere nella welcome page mentre l'utente sceglie.
|
||||
if (this.showRedirectOverlay() || this.showInstallOverlay()) {
|
||||
// Se stiamo attivamente installando o reindirizzando, NON nascondiamo il loader
|
||||
if (this.isInstalling() || this.isRedirecting()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Altrimenti, nascondiamo il loader per far entrare l'utente nell'app
|
||||
// Altrimenti, nascondiamo il loader per far entrare l'utente
|
||||
if ((window as any).PwaLoader) {
|
||||
(window as any).PwaLoader.hide();
|
||||
}
|
||||
@@ -95,6 +97,15 @@ export class AppComponent implements OnInit {
|
||||
// Set signal indicating startup version check is complete
|
||||
this.settingsService.isVersionCheckComplete.set(true);
|
||||
|
||||
// Handle PWA Launch Queue if supported (focus-existing launch behavior)
|
||||
if ('launchQueue' in window) {
|
||||
(window as any).launchQueue.setConsumer((launchParams: any) => {
|
||||
if (launchParams.targetURL) {
|
||||
this.handleLaunchUrl(launchParams.targetURL);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.route.queryParams.subscribe(params => {
|
||||
const protocolUrl = params['url'];
|
||||
if (protocolUrl && protocolUrl.startsWith('web+canti:')) {
|
||||
@@ -120,10 +131,73 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
});
|
||||
window.addEventListener('appinstalled', () => {
|
||||
console.log('[AppComponent] PWA appinstalled event caught.');
|
||||
localStorage.setItem('pwa-installed', 'true');
|
||||
this.isPwaInstalled.set(true);
|
||||
this.isInstalling.set(false);
|
||||
this.isRedirecting.set(true);
|
||||
this.showInstallOverlay.set(false);
|
||||
this.showRedirectOverlay.set(false);
|
||||
|
||||
if ((window as any).PwaLoader) {
|
||||
(window as any).PwaLoader.show();
|
||||
(window as any).PwaLoader.update({
|
||||
title: 'Chiudi il browser',
|
||||
desc: 'Applicazione installata con successo! Chiudi il browser e continua sulla PWA.',
|
||||
isRedirect: true
|
||||
});
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.href = this.protocolLink;
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
this.checkAndRedirectToPwa();
|
||||
}
|
||||
|
||||
handleLaunchUrl(urlStr: string) {
|
||||
try {
|
||||
const urlObj = new URL(urlStr);
|
||||
|
||||
// 1. Check if it's a protocol link inside query params (e.g. /?url=web+canti://...)
|
||||
const protocolUrl = urlObj.searchParams.get('url');
|
||||
if (protocolUrl && protocolUrl.startsWith('web+canti:')) {
|
||||
const cleanUrl = protocolUrl.replace('web+canti://', 'http://localhost/');
|
||||
const innerUrlObj = new URL(cleanUrl);
|
||||
|
||||
let targetPath = innerUrlObj.pathname;
|
||||
if (targetPath === '/open' || targetPath === '//open') {
|
||||
targetPath = '/';
|
||||
} else if (targetPath.startsWith('/open/')) {
|
||||
targetPath = targetPath.substring(5);
|
||||
}
|
||||
|
||||
const queryParams: any = {};
|
||||
innerUrlObj.searchParams.forEach((value, key) => {
|
||||
queryParams[key] = value;
|
||||
});
|
||||
|
||||
console.log('[AppComponent] Launch queue routing (protocol) to:', targetPath, queryParams);
|
||||
this.router.navigate([targetPath], { queryParams, replaceUrl: true });
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Otherwise, route directly to the pathname and query params of the URL
|
||||
let targetPath = urlObj.pathname;
|
||||
const queryParams: any = {};
|
||||
urlObj.searchParams.forEach((value, key) => {
|
||||
queryParams[key] = value;
|
||||
});
|
||||
|
||||
console.log('[AppComponent] Launch queue routing (direct) to:', targetPath, queryParams);
|
||||
this.router.navigate([targetPath], { queryParams, replaceUrl: true });
|
||||
} catch (e) {
|
||||
console.error('Failed to parse launch url:', urlStr, e);
|
||||
}
|
||||
}
|
||||
|
||||
async checkVersionSync(): Promise<boolean> {
|
||||
// Controlla SEMPRE version.json per primo — è il modo più affidabile per
|
||||
// rilevare un disallineamento di versione, indipendentemente dallo stato del SW.
|
||||
@@ -304,30 +378,49 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
if (isInstalled) {
|
||||
const skipRedirect = sessionStorage.getItem('skip-pwa-redirect') === 'true';
|
||||
if (!skipRedirect) {
|
||||
this.showRedirectOverlay.set(true);
|
||||
this.redirectFailed.set(false);
|
||||
if ((window as any).PwaLoader) {
|
||||
(window as any).PwaLoader.update({ isRedirect: true });
|
||||
// Se non è rilevata in localStorage/relatedApps ed è Android o Desktop con supporto ai prompt:
|
||||
// attendiamo 1.5s per dare tempo all'evento 'beforeinstallprompt' di scattare.
|
||||
// Se non scatta, significa che l'app è già installata.
|
||||
if (!isInstalled && !this.settingsService.isIos() && ('onbeforeinstallprompt' in window)) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1500));
|
||||
isInstalled = localStorage.getItem('pwa-installed') === 'true';
|
||||
if (!isInstalled) {
|
||||
const hasPrompt = this.settingsService.showInstallButton() || this.settingsService.deferredPrompt();
|
||||
if (!hasPrompt) {
|
||||
console.log('[AppComponent] PWA detected as already installed (onbeforeinstallprompt supported but no prompt fired).');
|
||||
isInstalled = true;
|
||||
localStorage.setItem('pwa-installed', 'true');
|
||||
}
|
||||
// Tentiamo il reindirizzamento automatico
|
||||
setTimeout(() => {
|
||||
window.location.href = this.protocolLink;
|
||||
|
||||
// Se dopo 2 secondi l'utente è ancora qui, probabilmente l'app non è installata
|
||||
setTimeout(() => {
|
||||
if (this.showRedirectOverlay()) {
|
||||
this.redirectFailed.set(true);
|
||||
localStorage.setItem('pwa-installed', 'false');
|
||||
if ((window as any).PwaLoader) {
|
||||
(window as any).PwaLoader.hide();
|
||||
}
|
||||
}
|
||||
}, 2000);
|
||||
}, 800);
|
||||
}
|
||||
}
|
||||
|
||||
this.isPwaInstalled.set(isInstalled);
|
||||
|
||||
if (isInstalled) {
|
||||
if (sessionStorage.getItem('skip-pwa-redirect') === 'true') {
|
||||
this.showRedirectOverlay.set(false);
|
||||
this.checkLoaderDismissal();
|
||||
return;
|
||||
}
|
||||
this.showRedirectOverlay.set(true);
|
||||
this.redirectFailed.set(false);
|
||||
if ((window as any).PwaLoader) {
|
||||
(window as any).PwaLoader.update({ isRedirect: true });
|
||||
}
|
||||
// Tentiamo il reindirizzamento automatico
|
||||
setTimeout(() => {
|
||||
window.location.href = this.protocolLink;
|
||||
|
||||
// Se dopo 2 secondi l'utente è ancora qui, mostriamo lo stato fallito per aprire manualmente o indicare la disinstallazione
|
||||
setTimeout(() => {
|
||||
if (this.showRedirectOverlay()) {
|
||||
this.redirectFailed.set(true);
|
||||
if ((window as any).PwaLoader) {
|
||||
(window as any).PwaLoader.hide();
|
||||
}
|
||||
}
|
||||
}, 2000);
|
||||
}, 800);
|
||||
} else {
|
||||
// Se non è installata, proponiamo l'installazione immediata per evitare la cache del browser e avere un'esperienza ottimale
|
||||
const skipInstall = sessionStorage.getItem('skip-pwa-install') === 'true';
|
||||
@@ -335,6 +428,8 @@ export class AppComponent implements OnInit {
|
||||
const hasDesktopPrompt = this.settingsService.showInstallButton() || this.settingsService.deferredPrompt();
|
||||
if (!skipInstall && (isMobile || hasDesktopPrompt)) {
|
||||
this.showInstallOverlay.set(true);
|
||||
} else {
|
||||
this.checkLoaderDismissal();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,22 +455,80 @@ export class AppComponent implements OnInit {
|
||||
stayInBrowser() {
|
||||
sessionStorage.setItem('skip-pwa-redirect', 'true');
|
||||
this.showRedirectOverlay.set(false);
|
||||
this.checkLoaderDismissal();
|
||||
}
|
||||
|
||||
stayInBrowserForceUninstallCheck() {
|
||||
localStorage.setItem('pwa-installed', 'false');
|
||||
this.isPwaInstalled.set(false);
|
||||
this.stayInBrowser();
|
||||
}
|
||||
|
||||
closeInstallOverlay() {
|
||||
sessionStorage.setItem('skip-pwa-install', 'true');
|
||||
this.showInstallOverlay.set(false);
|
||||
this.checkLoaderDismissal();
|
||||
}
|
||||
|
||||
async triggerInstall() {
|
||||
await this.settingsService.installPwa();
|
||||
this.closeInstallOverlay();
|
||||
this.isInstalling.set(true);
|
||||
this.showInstallOverlay.set(false);
|
||||
if ((window as any).PwaLoader) {
|
||||
(window as any).PwaLoader.show();
|
||||
(window as any).PwaLoader.update({
|
||||
title: 'Installazione in corso...',
|
||||
desc: 'Completa l\'installazione tramite la finestra del browser.'
|
||||
});
|
||||
}
|
||||
|
||||
const outcome = await this.settingsService.installPwa();
|
||||
if (outcome === 'accepted') {
|
||||
this.isInstalling.set(false);
|
||||
this.isRedirecting.set(true);
|
||||
if ((window as any).PwaLoader) {
|
||||
(window as any).PwaLoader.update({
|
||||
title: 'Apertura Applicazione...',
|
||||
desc: 'Installazione completata! Chiudi il browser e continua sulla PWA.',
|
||||
isRedirect: true
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.isInstalling.set(false);
|
||||
this.isRedirecting.set(false);
|
||||
this.showInstallOverlay.set(true);
|
||||
this.checkLoaderDismissal();
|
||||
}
|
||||
}
|
||||
|
||||
async triggerInstallFromRedirect() {
|
||||
await this.settingsService.installPwa();
|
||||
sessionStorage.setItem('skip-pwa-redirect', 'true');
|
||||
this.isInstalling.set(true);
|
||||
this.showRedirectOverlay.set(false);
|
||||
if ((window as any).PwaLoader) {
|
||||
(window as any).PwaLoader.show();
|
||||
(window as any).PwaLoader.update({
|
||||
title: 'Installazione in corso...',
|
||||
desc: 'Completa l\'installazione tramite la finestra del browser.'
|
||||
});
|
||||
}
|
||||
|
||||
const outcome = await this.settingsService.installPwa();
|
||||
if (outcome === 'accepted') {
|
||||
sessionStorage.setItem('skip-pwa-redirect', 'true');
|
||||
this.isInstalling.set(false);
|
||||
this.isRedirecting.set(true);
|
||||
if ((window as any).PwaLoader) {
|
||||
(window as any).PwaLoader.update({
|
||||
title: 'Apertura Applicazione...',
|
||||
desc: 'Installazione completata! Chiudi il browser e continua sulla PWA.',
|
||||
isRedirect: true
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.isInstalling.set(false);
|
||||
this.isRedirecting.set(false);
|
||||
this.showRedirectOverlay.set(true);
|
||||
this.checkLoaderDismissal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user