fix: prevent install prompt showing in installed PWA
- Improve installation status detection logic - Add proper DOM cleanup when PWA is installed - Enhance monitoring for installation state changes - Fix shouldShowPrompt() logic to always check current status - Add forceInstallationCheck() method for manual status updates
This commit is contained in:
@@ -14,10 +14,8 @@ class PWAInstallPrompt {
|
|||||||
init() {
|
init() {
|
||||||
console.log('💿 PWA Install Prompt initializing...');
|
console.log('💿 PWA Install Prompt initializing...');
|
||||||
|
|
||||||
// Сначала проверяем статус установки
|
|
||||||
this.checkInstallationStatus();
|
this.checkInstallationStatus();
|
||||||
|
|
||||||
// Если уже установлено, не инициализируем остальное
|
|
||||||
if (this.isInstalled) {
|
if (this.isInstalled) {
|
||||||
console.log('💿 App already installed, skipping initialization');
|
console.log('💿 App already installed, skipping initialization');
|
||||||
return;
|
return;
|
||||||
@@ -27,7 +25,6 @@ class PWAInstallPrompt {
|
|||||||
this.createInstallButton();
|
this.createInstallButton();
|
||||||
this.loadInstallPreferences();
|
this.loadInstallPreferences();
|
||||||
|
|
||||||
// Проверяем статус установки периодически для iOS
|
|
||||||
if (this.isIOSSafari()) {
|
if (this.isIOSSafari()) {
|
||||||
this.startInstallationMonitoring();
|
this.startInstallationMonitoring();
|
||||||
}
|
}
|
||||||
@@ -38,7 +35,6 @@ class PWAInstallPrompt {
|
|||||||
checkInstallationStatus() {
|
checkInstallationStatus() {
|
||||||
console.log('🔍 Checking PWA installation status...');
|
console.log('🔍 Checking PWA installation status...');
|
||||||
|
|
||||||
// Проверяем различные способы определения установки PWA
|
|
||||||
const isStandalone = window.matchMedia('(display-mode: standalone)').matches;
|
const isStandalone = window.matchMedia('(display-mode: standalone)').matches;
|
||||||
const isIOSStandalone = window.navigator.standalone === true;
|
const isIOSStandalone = window.navigator.standalone === true;
|
||||||
const hasInstallPreference = this.loadInstallPreferences().installed;
|
const hasInstallPreference = this.loadInstallPreferences().installed;
|
||||||
@@ -50,17 +46,14 @@ class PWAInstallPrompt {
|
|||||||
userAgent: navigator.userAgent.slice(0, 100)
|
userAgent: navigator.userAgent.slice(0, 100)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Проверяем, установлено ли приложение
|
|
||||||
if (isStandalone || isIOSStandalone || hasInstallPreference) {
|
if (isStandalone || isIOSStandalone || hasInstallPreference) {
|
||||||
this.isInstalled = true;
|
this.isInstalled = true;
|
||||||
console.log('📱 App is already installed as PWA');
|
console.log('📱 App is already installed as PWA');
|
||||||
document.body.classList.add('pwa-installed');
|
document.body.classList.add('pwa-installed');
|
||||||
document.body.classList.remove('pwa-browser');
|
document.body.classList.remove('pwa-browser');
|
||||||
|
|
||||||
// Скрываем все промпты установки
|
|
||||||
this.hideInstallPrompts();
|
this.hideInstallPrompts();
|
||||||
|
|
||||||
// Если это iOS, добавляем специальный класс
|
|
||||||
if (this.isIOSSafari()) {
|
if (this.isIOSSafari()) {
|
||||||
document.body.classList.add('ios-pwa');
|
document.body.classList.add('ios-pwa');
|
||||||
}
|
}
|
||||||
@@ -69,7 +62,6 @@ class PWAInstallPrompt {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если не установлено, добавляем соответствующие классы
|
|
||||||
this.isInstalled = false;
|
this.isInstalled = false;
|
||||||
document.body.classList.add('pwa-browser');
|
document.body.classList.add('pwa-browser');
|
||||||
document.body.classList.remove('pwa-installed');
|
document.body.classList.remove('pwa-installed');
|
||||||
@@ -83,7 +75,6 @@ class PWAInstallPrompt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
startInstallationMonitoring() {
|
startInstallationMonitoring() {
|
||||||
// Для iOS Safari мониторим изменения в standalone режиме
|
|
||||||
let wasStandalone = window.navigator.standalone;
|
let wasStandalone = window.navigator.standalone;
|
||||||
|
|
||||||
const checkStandalone = () => {
|
const checkStandalone = () => {
|
||||||
@@ -97,24 +88,20 @@ class PWAInstallPrompt {
|
|||||||
document.body.classList.remove('pwa-browser', 'ios-safari');
|
document.body.classList.remove('pwa-browser', 'ios-safari');
|
||||||
document.body.classList.add('pwa-installed', 'ios-pwa');
|
document.body.classList.add('pwa-installed', 'ios-pwa');
|
||||||
|
|
||||||
// Сохраняем предпочтение установки
|
|
||||||
this.saveInstallPreference('installed', true);
|
this.saveInstallPreference('installed', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
wasStandalone = isStandalone;
|
wasStandalone = isStandalone;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Проверяем каждые 2 секунды
|
|
||||||
setInterval(checkStandalone, 2000);
|
setInterval(checkStandalone, 2000);
|
||||||
|
|
||||||
// Также проверяем при изменении видимости страницы
|
|
||||||
window.addEventListener('visibilitychange', () => {
|
window.addEventListener('visibilitychange', () => {
|
||||||
if (!document.hidden) {
|
if (!document.hidden) {
|
||||||
setTimeout(checkStandalone, 1000);
|
setTimeout(checkStandalone, 1000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Проверяем при фокусе окна
|
|
||||||
window.addEventListener('focus', () => {
|
window.addEventListener('focus', () => {
|
||||||
setTimeout(checkStandalone, 500);
|
setTimeout(checkStandalone, 500);
|
||||||
});
|
});
|
||||||
@@ -126,12 +113,10 @@ class PWAInstallPrompt {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.deferredPrompt = event;
|
this.deferredPrompt = event;
|
||||||
|
|
||||||
// Повторно проверяем статус установки
|
|
||||||
if (this.checkInstallationStatus()) {
|
if (this.checkInstallationStatus()) {
|
||||||
return; // Если установлено, не показываем промпт
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Показываем промпт только если приложение не установлено
|
|
||||||
if (!this.isInstalled && this.shouldShowPrompt()) {
|
if (!this.isInstalled && this.shouldShowPrompt()) {
|
||||||
setTimeout(() => this.showInstallOptions(), 1000);
|
setTimeout(() => this.showInstallOptions(), 1000);
|
||||||
}
|
}
|
||||||
@@ -148,7 +133,6 @@ class PWAInstallPrompt {
|
|||||||
document.body.classList.add('pwa-installed');
|
document.body.classList.add('pwa-installed');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Дополнительная проверка для всех устройств при изменении видимости
|
|
||||||
window.addEventListener('visibilitychange', () => {
|
window.addEventListener('visibilitychange', () => {
|
||||||
if (document.hidden) return;
|
if (document.hidden) return;
|
||||||
|
|
||||||
@@ -156,7 +140,6 @@ class PWAInstallPrompt {
|
|||||||
const wasInstalled = this.isInstalled;
|
const wasInstalled = this.isInstalled;
|
||||||
this.checkInstallationStatus();
|
this.checkInstallationStatus();
|
||||||
|
|
||||||
// Если статус изменился с "не установлено" на "установлено"
|
|
||||||
if (!wasInstalled && this.isInstalled) {
|
if (!wasInstalled && this.isInstalled) {
|
||||||
console.log('✅ PWA installation detected on visibility change');
|
console.log('✅ PWA installation detected on visibility change');
|
||||||
this.hideInstallPrompts();
|
this.hideInstallPrompts();
|
||||||
@@ -165,7 +148,6 @@ class PWAInstallPrompt {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Проверяем при фокусе окна
|
|
||||||
window.addEventListener('focus', () => {
|
window.addEventListener('focus', () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const wasInstalled = this.isInstalled;
|
const wasInstalled = this.isInstalled;
|
||||||
@@ -181,7 +163,6 @@ class PWAInstallPrompt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createInstallButton() {
|
createInstallButton() {
|
||||||
// Если уже установлено, не создаем кнопку
|
|
||||||
if (this.isInstalled) {
|
if (this.isInstalled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -202,14 +183,12 @@ class PWAInstallPrompt {
|
|||||||
</button>
|
</button>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Обработчик для установки
|
|
||||||
this.installButton.addEventListener('click', (e) => {
|
this.installButton.addEventListener('click', (e) => {
|
||||||
if (!e.target.classList.contains('close-btn')) {
|
if (!e.target.classList.contains('close-btn')) {
|
||||||
this.handleInstallClick();
|
this.handleInstallClick();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Обработчик для закрытия
|
|
||||||
const closeBtn = this.installButton.querySelector('.close-btn');
|
const closeBtn = this.installButton.querySelector('.close-btn');
|
||||||
closeBtn.addEventListener('click', (e) => {
|
closeBtn.addEventListener('click', (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -220,7 +199,6 @@ class PWAInstallPrompt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createInstallBanner() {
|
createInstallBanner() {
|
||||||
// Если уже установлено, не создаем баннер
|
|
||||||
if (this.isInstalled || this.installBanner) {
|
if (this.isInstalled || this.installBanner) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -268,7 +246,6 @@ class PWAInstallPrompt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showInstallOptions() {
|
showInstallOptions() {
|
||||||
// Всегда проверяем статус установки перед показом
|
|
||||||
if (this.checkInstallationStatus()) {
|
if (this.checkInstallationStatus()) {
|
||||||
console.log('💿 App is installed, not showing install options');
|
console.log('💿 App is installed, not showing install options');
|
||||||
return;
|
return;
|
||||||
@@ -284,7 +261,6 @@ class PWAInstallPrompt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showInstallButton() {
|
showInstallButton() {
|
||||||
// Проверяем статус установки
|
|
||||||
if (this.checkInstallationStatus()) {
|
if (this.checkInstallationStatus()) {
|
||||||
console.log('💿 App is installed, not showing install button');
|
console.log('💿 App is installed, not showing install button');
|
||||||
return;
|
return;
|
||||||
@@ -308,7 +284,6 @@ class PWAInstallPrompt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showInstallBanner() {
|
showInstallBanner() {
|
||||||
// Проверяем статус установки
|
|
||||||
if (this.checkInstallationStatus()) {
|
if (this.checkInstallationStatus()) {
|
||||||
console.log('💿 App is installed, not showing install banner');
|
console.log('💿 App is installed, not showing install banner');
|
||||||
return;
|
return;
|
||||||
@@ -335,7 +310,6 @@ class PWAInstallPrompt {
|
|||||||
|
|
||||||
if (this.installButton) {
|
if (this.installButton) {
|
||||||
this.installButton.classList.add('hidden');
|
this.installButton.classList.add('hidden');
|
||||||
// Полностью удаляем кнопку если приложение установлено
|
|
||||||
if (this.isInstalled) {
|
if (this.isInstalled) {
|
||||||
this.installButton.remove();
|
this.installButton.remove();
|
||||||
this.installButton = null;
|
this.installButton = null;
|
||||||
@@ -346,7 +320,6 @@ class PWAInstallPrompt {
|
|||||||
if (this.installBanner) {
|
if (this.installBanner) {
|
||||||
this.installBanner.classList.remove('show');
|
this.installBanner.classList.remove('show');
|
||||||
this.installBanner.style.transform = 'translateY(100%)';
|
this.installBanner.style.transform = 'translateY(100%)';
|
||||||
// Полностью удаляем баннер если приложение установлено
|
|
||||||
if (this.isInstalled) {
|
if (this.isInstalled) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (this.installBanner) {
|
if (this.installBanner) {
|
||||||
@@ -379,7 +352,7 @@ class PWAInstallPrompt {
|
|||||||
|
|
||||||
if (result.outcome === 'accepted') {
|
if (result.outcome === 'accepted') {
|
||||||
console.log('✅ User accepted install prompt');
|
console.log('✅ User accepted install prompt');
|
||||||
this.isInstalled = true; // Устанавливаем флаг сразу
|
this.isInstalled = true;
|
||||||
this.hideInstallPrompts();
|
this.hideInstallPrompts();
|
||||||
this.saveInstallPreference('accepted', true);
|
this.saveInstallPreference('accepted', true);
|
||||||
this.saveInstallPreference('installed', true);
|
this.saveInstallPreference('installed', true);
|
||||||
@@ -550,12 +523,10 @@ class PWAInstallPrompt {
|
|||||||
setTimeout(() => notification.remove(), 300);
|
setTimeout(() => notification.remove(), 300);
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
// Скрываем все промпты установки
|
|
||||||
this.hideInstallPrompts();
|
this.hideInstallPrompts();
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldShowPrompt() {
|
shouldShowPrompt() {
|
||||||
// Всегда проверяем актуальный статус установки
|
|
||||||
if (this.checkInstallationStatus()) {
|
if (this.checkInstallationStatus()) {
|
||||||
console.log('💿 App is installed, not showing prompt');
|
console.log('💿 App is installed, not showing prompt');
|
||||||
return false;
|
return false;
|
||||||
@@ -563,7 +534,6 @@ class PWAInstallPrompt {
|
|||||||
|
|
||||||
const preferences = this.loadInstallPreferences();
|
const preferences = this.loadInstallPreferences();
|
||||||
|
|
||||||
// Проверяем, не было ли приложение уже установлено
|
|
||||||
if (preferences.installed) {
|
if (preferences.installed) {
|
||||||
console.log('💿 Installation preference found, marking as installed');
|
console.log('💿 Installation preference found, marking as installed');
|
||||||
this.isInstalled = true;
|
this.isInstalled = true;
|
||||||
@@ -691,7 +661,6 @@ class PWAInstallPrompt {
|
|||||||
|
|
||||||
// Public API methods
|
// Public API methods
|
||||||
showInstallPrompt() {
|
showInstallPrompt() {
|
||||||
// Проверяем статус перед показом
|
|
||||||
if (this.checkInstallationStatus()) {
|
if (this.checkInstallationStatus()) {
|
||||||
console.log('💿 App already installed, not showing prompt');
|
console.log('💿 App already installed, not showing prompt');
|
||||||
return;
|
return;
|
||||||
@@ -711,7 +680,6 @@ class PWAInstallPrompt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getInstallStatus() {
|
getInstallStatus() {
|
||||||
// Проверяем актуальный статус
|
|
||||||
this.checkInstallationStatus();
|
this.checkInstallationStatus();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -735,7 +703,6 @@ class PWAInstallPrompt {
|
|||||||
console.log('📡 Service Worker registration set for PWA Install Prompt');
|
console.log('📡 Service Worker registration set for PWA Install Prompt');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Метод для принудительной проверки статуса установки
|
|
||||||
forceInstallationCheck() {
|
forceInstallationCheck() {
|
||||||
console.log('🔄 Force checking installation status...');
|
console.log('🔄 Force checking installation status...');
|
||||||
this.installationChecked = false;
|
this.installationChecked = false;
|
||||||
@@ -766,10 +733,8 @@ if (typeof window !== 'undefined') {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Дополнительная проверка при полной загрузке страницы
|
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
if (window.pwaInstallPrompt) {
|
if (window.pwaInstallPrompt) {
|
||||||
// Проверяем статус установки через небольшую задержку
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.pwaInstallPrompt.forceInstallationCheck();
|
window.pwaInstallPrompt.forceInstallationCheck();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|||||||
Reference in New Issue
Block a user