✨ Обновлены инструкции и функциональность PWA
- Изменена структура инструкций по тестированию PWA, добавлена диагностическая страница для отладки. - Обновлен manifest.json с добавлением поля "id". - Реализована задержка при отображении кнопки установки для улучшения пользовательского опыта. - Добавлены функции для проверки возможности установки PWA и отображения инструкций для мобильных устройств.
This commit is contained in:
parent
95401328c4
commit
d6dc1d76a0
@ -22,17 +22,22 @@
|
||||
|
||||
## Как протестировать
|
||||
|
||||
### 1. Откройте тестовую страницу для мобильных устройств
|
||||
### 1. Откройте диагностическую страницу PWA
|
||||
```
|
||||
http://localhost:3000/pwa-debug.html
|
||||
```
|
||||
|
||||
### 2. Откройте тестовую страницу для мобильных устройств
|
||||
```
|
||||
http://localhost:3000/mobile-pwa-test.html
|
||||
```
|
||||
|
||||
### 2. Откройте обычную тестовую страницу
|
||||
### 3. Откройте обычную тестовую страницу
|
||||
```
|
||||
http://localhost:3000/test-pwa.html
|
||||
```
|
||||
|
||||
### 3. Проверьте требования PWA
|
||||
### 4. Проверьте требования PWA
|
||||
На мобильной тестовой странице автоматически проверяются все требования:
|
||||
- ✅ HTTPS или localhost
|
||||
- ✅ Service Worker
|
||||
@ -40,12 +45,12 @@ http://localhost:3000/test-pwa.html
|
||||
- ✅ Иконки
|
||||
- ❌ Уже установлено (должно быть красным, если не установлено)
|
||||
|
||||
### 4. Установка приложения
|
||||
### 5. Установка приложения
|
||||
- Если все проверки пройдены, появится кнопка "Установить приложение"
|
||||
- Нажмите на неё для установки PWA
|
||||
- Следуйте инструкциям браузера или используйте инструкции на странице
|
||||
|
||||
### 5. Проверка в разных браузерах
|
||||
### 6. Проверка в разных браузерах
|
||||
|
||||
#### Chrome/Edge:
|
||||
- Откройте DevTools (F12)
|
||||
@ -96,6 +101,9 @@ http://localhost:3000/test-pwa.html
|
||||
- Улучшенная проверка установки PWA
|
||||
- Поддержка различных режимов отображения
|
||||
- **Кнопка установки показывается только на мобильных устройствах**
|
||||
- Принудительная проверка возможности установки
|
||||
- Специальные инструкции для Android и iOS
|
||||
- Диагностическая страница для отладки PWA
|
||||
|
||||
## Возможные проблемы и решения
|
||||
|
||||
@ -151,8 +159,22 @@ window.debugPWA();
|
||||
|
||||
// Проверить Service Worker
|
||||
navigator.serviceWorker.getRegistrations().then(console.log);
|
||||
|
||||
// Проверить возможность установки
|
||||
window.checkInstallability();
|
||||
|
||||
// Принудительная попытка установки
|
||||
window.forceInstall();
|
||||
```
|
||||
|
||||
### Диагностическая страница
|
||||
Используйте `http://localhost:3000/pwa-debug.html` для:
|
||||
- Детальной диагностики всех требований PWA
|
||||
- Проверки загрузки манифеста и Service Worker
|
||||
- Отображения информации о браузере и устройстве
|
||||
- Просмотра ошибок консоли
|
||||
- Тестирования установки PWA
|
||||
|
||||
### Lighthouse
|
||||
Запустите аудит Lighthouse в Chrome DevTools:
|
||||
1. Откройте DevTools (F12)
|
||||
@ -166,6 +188,7 @@ navigator.serviceWorker.getRegistrations().then(console.log);
|
||||
- ✅ `http://localhost:3000/sw.js` - должен возвращать JavaScript
|
||||
- ✅ `http://localhost:3000/icons/icon-192x192.png` - должен возвращать PNG
|
||||
- ✅ `http://localhost:3000/icons/icon-512x512.png` - должен возвращать PNG
|
||||
- ✅ `http://localhost:3000/pwa-debug.html` - диагностическая страница PWA
|
||||
- ✅ `http://localhost:3000/mobile-pwa-test.html` - мобильная тестовая страница
|
||||
- ✅ `http://localhost:3000/test-pwa.html` - обычная тестовая страница
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
"orientation": "portrait-primary",
|
||||
"scope": "/",
|
||||
"lang": "ru",
|
||||
"id": "/",
|
||||
"categories": ["productivity", "utilities"],
|
||||
"screenshots": [
|
||||
{
|
||||
|
||||
411
public/pwa-debug.html
Normal file
411
public/pwa-debug.html
Normal file
@ -0,0 +1,411 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Диагностика PWA - NoteJS</title>
|
||||
|
||||
<!-- PWA Meta Tags -->
|
||||
<meta name="description" content="Диагностика PWA для NoteJS" />
|
||||
<meta name="theme-color" content="#007bff" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="apple-mobile-web-app-title" content="NoteJS" />
|
||||
<meta name="apple-touch-fullscreen" content="yes" />
|
||||
<meta name="msapplication-TileColor" content="#007bff" />
|
||||
<meta name="msapplication-config" content="/browserconfig.xml" />
|
||||
<meta name="msapplication-TileImage" content="/icons/icon-144x144.png" />
|
||||
<meta name="application-name" content="NoteJS" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
|
||||
<!-- Icons -->
|
||||
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/icons/icon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/icons/icon-16x16.png" />
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="/icons/icon-48x48.png" />
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="/icons/icon-48x48.png" />
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="/icons/icon-72x72.png" />
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="/icons/icon-72x72.png" />
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="/icons/icon-128x128.png" />
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="/icons/icon-128x128.png" />
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="/icons/icon-144x144.png" />
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="/icons/icon-152x152.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/icons/icon-192x192.png" />
|
||||
<link rel="mask-icon" href="/icon.svg" color="#007bff" />
|
||||
|
||||
<!-- Manifest -->
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<!-- Styles -->
|
||||
<link rel="stylesheet" href="/style.css" />
|
||||
|
||||
<style>
|
||||
.debug-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.debug-section {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.debug-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.debug-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.status {
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status.pass {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.status.fail {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.status.warning {
|
||||
background: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.debug-code {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
white-space: pre-wrap;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.install-button {
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px 24px;
|
||||
border-radius: 6px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.install-button:hover {
|
||||
background: #0056b3;
|
||||
}
|
||||
|
||||
.install-button:disabled {
|
||||
background: #6c757d;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.success-message {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="debug-container">
|
||||
<h1>🔍 Диагностика PWA</h1>
|
||||
|
||||
<div class="debug-section">
|
||||
<h3>Основные требования PWA</h3>
|
||||
<div id="basic-checks">
|
||||
<div class="debug-item">
|
||||
<span>HTTPS или localhost</span>
|
||||
<span class="status" id="https-check">Проверка...</span>
|
||||
</div>
|
||||
<div class="debug-item">
|
||||
<span>Service Worker</span>
|
||||
<span class="status" id="sw-check">Проверка...</span>
|
||||
</div>
|
||||
<div class="debug-item">
|
||||
<span>Manifest</span>
|
||||
<span class="status" id="manifest-check">Проверка...</span>
|
||||
</div>
|
||||
<div class="debug-item">
|
||||
<span>Иконки</span>
|
||||
<span class="status" id="icons-check">Проверка...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="debug-section">
|
||||
<h3>Детальная диагностика</h3>
|
||||
<div id="detailed-checks">
|
||||
<div class="debug-item">
|
||||
<span>Manifest загружается</span>
|
||||
<span class="status" id="manifest-load-check">Проверка...</span>
|
||||
</div>
|
||||
<div class="debug-item">
|
||||
<span>Service Worker регистрируется</span>
|
||||
<span class="status" id="sw-register-check">Проверка...</span>
|
||||
</div>
|
||||
<div class="debug-item">
|
||||
<span>Иконки доступны</span>
|
||||
<span class="status" id="icons-available-check">Проверка...</span>
|
||||
</div>
|
||||
<div class="debug-item">
|
||||
<span>beforeinstallprompt событие</span>
|
||||
<span class="status" id="install-prompt-check">Проверка...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="debug-section">
|
||||
<h3>Установка приложения</h3>
|
||||
<button id="install-button" class="install-button" disabled>
|
||||
Установить приложение
|
||||
</button>
|
||||
<div id="install-status"></div>
|
||||
</div>
|
||||
|
||||
<div class="debug-section">
|
||||
<h3>Информация о манифесте</h3>
|
||||
<div id="manifest-info" class="debug-code">Загрузка...</div>
|
||||
</div>
|
||||
|
||||
<div class="debug-section">
|
||||
<h3>Информация о Service Worker</h3>
|
||||
<div id="sw-info" class="debug-code">Загрузка...</div>
|
||||
</div>
|
||||
|
||||
<div class="debug-section">
|
||||
<h3>Информация о браузере</h3>
|
||||
<div id="browser-info" class="debug-code">Загрузка...</div>
|
||||
</div>
|
||||
|
||||
<div class="debug-section">
|
||||
<h3>Ошибки консоли</h3>
|
||||
<div id="console-errors" class="debug-code">Нет ошибок</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let deferredPrompt;
|
||||
let consoleErrors = [];
|
||||
|
||||
// Перехватываем ошибки консоли
|
||||
const originalError = console.error;
|
||||
console.error = function(...args) {
|
||||
consoleErrors.push(args.join(' '));
|
||||
originalError.apply(console, args);
|
||||
};
|
||||
|
||||
// Проверка основных требований PWA
|
||||
function checkBasicRequirements() {
|
||||
// HTTPS или localhost
|
||||
const isSecure = location.protocol === 'https:' || location.hostname === 'localhost';
|
||||
document.getElementById('https-check').textContent = isSecure ? '✅ Да' : '❌ Нет';
|
||||
document.getElementById('https-check').className = `status ${isSecure ? 'pass' : 'fail'}`;
|
||||
|
||||
// Service Worker
|
||||
const hasSW = 'serviceWorker' in navigator;
|
||||
document.getElementById('sw-check').textContent = hasSW ? '✅ Да' : '❌ Нет';
|
||||
document.getElementById('sw-check').className = `status ${hasSW ? 'pass' : 'fail'}`;
|
||||
|
||||
// Manifest
|
||||
const hasManifest = document.querySelector('link[rel="manifest"]') !== null;
|
||||
document.getElementById('manifest-check').textContent = hasManifest ? '✅ Да' : '❌ Нет';
|
||||
document.getElementById('manifest-check').className = `status ${hasManifest ? 'pass' : 'fail'}`;
|
||||
|
||||
// Иконки
|
||||
const hasIcons = document.querySelector('link[rel="icon"]') !== null;
|
||||
document.getElementById('icons-check').textContent = hasIcons ? '✅ Да' : '❌ Нет';
|
||||
document.getElementById('icons-check').className = `status ${hasIcons ? 'pass' : 'fail'}`;
|
||||
}
|
||||
|
||||
// Детальная диагностика
|
||||
async function detailedDiagnostics() {
|
||||
// Проверка загрузки манифеста
|
||||
try {
|
||||
const manifestResponse = await fetch('/manifest.json');
|
||||
const manifest = await manifestResponse.json();
|
||||
document.getElementById('manifest-load-check').textContent = '✅ Загружен';
|
||||
document.getElementById('manifest-load-check').className = 'status pass';
|
||||
|
||||
// Отображаем информацию о манифесте
|
||||
document.getElementById('manifest-info').textContent = JSON.stringify(manifest, null, 2);
|
||||
} catch (error) {
|
||||
document.getElementById('manifest-load-check').textContent = '❌ Ошибка загрузки';
|
||||
document.getElementById('manifest-load-check').className = 'status fail';
|
||||
document.getElementById('manifest-info').textContent = `Ошибка: ${error.message}`;
|
||||
}
|
||||
|
||||
// Проверка регистрации Service Worker
|
||||
if ('serviceWorker' in navigator) {
|
||||
try {
|
||||
const registration = await navigator.serviceWorker.getRegistration();
|
||||
if (registration) {
|
||||
document.getElementById('sw-register-check').textContent = '✅ Зарегистрирован';
|
||||
document.getElementById('sw-register-check').className = 'status pass';
|
||||
|
||||
// Отображаем информацию о Service Worker
|
||||
document.getElementById('sw-info').textContent = JSON.stringify({
|
||||
scope: registration.scope,
|
||||
state: registration.active ? registration.active.state : 'не активен',
|
||||
scriptURL: registration.active ? registration.active.scriptURL : 'не доступен'
|
||||
}, null, 2);
|
||||
} else {
|
||||
document.getElementById('sw-register-check').textContent = '❌ Не зарегистрирован';
|
||||
document.getElementById('sw-register-check').className = 'status fail';
|
||||
}
|
||||
} catch (error) {
|
||||
document.getElementById('sw-register-check').textContent = '❌ Ошибка';
|
||||
document.getElementById('sw-register-check').className = 'status fail';
|
||||
}
|
||||
}
|
||||
|
||||
// Проверка доступности иконок
|
||||
const iconSizes = ['192x192', '512x512'];
|
||||
let iconsAvailable = 0;
|
||||
|
||||
for (const size of iconSizes) {
|
||||
try {
|
||||
const response = await fetch(`/icons/icon-${size}.png`);
|
||||
if (response.ok) {
|
||||
iconsAvailable++;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Ошибка загрузки иконки ${size}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
if (iconsAvailable === iconSizes.length) {
|
||||
document.getElementById('icons-available-check').textContent = '✅ Все доступны';
|
||||
document.getElementById('icons-available-check').className = 'status pass';
|
||||
} else {
|
||||
document.getElementById('icons-available-check').textContent = `⚠️ ${iconsAvailable}/${iconSizes.length} доступны`;
|
||||
document.getElementById('icons-available-check').className = 'status warning';
|
||||
}
|
||||
|
||||
// Информация о браузере
|
||||
document.getElementById('browser-info').textContent = JSON.stringify({
|
||||
userAgent: navigator.userAgent,
|
||||
platform: navigator.platform,
|
||||
language: navigator.language,
|
||||
onLine: navigator.onLine,
|
||||
cookieEnabled: navigator.cookieEnabled,
|
||||
maxTouchPoints: navigator.maxTouchPoints,
|
||||
displayMode: window.matchMedia('(display-mode: standalone)').matches ? 'standalone' : 'browser',
|
||||
standalone: window.navigator.standalone
|
||||
}, null, 2);
|
||||
}
|
||||
|
||||
// Регистрация Service Worker
|
||||
function registerServiceWorker() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/sw.js')
|
||||
.then((registration) => {
|
||||
console.log('SW зарегистрирован успешно:', registration.scope);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('Ошибка регистрации SW:', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Обработка установки
|
||||
window.addEventListener('beforeinstallprompt', (e) => {
|
||||
console.log('beforeinstallprompt событие получено');
|
||||
e.preventDefault();
|
||||
deferredPrompt = e;
|
||||
|
||||
document.getElementById('install-prompt-check').textContent = '✅ Получено';
|
||||
document.getElementById('install-prompt-check').className = 'status pass';
|
||||
|
||||
const installButton = document.getElementById('install-button');
|
||||
installButton.disabled = false;
|
||||
installButton.textContent = '📱 Установить приложение';
|
||||
});
|
||||
|
||||
// Обработка успешной установки
|
||||
window.addEventListener('appinstalled', () => {
|
||||
console.log('PWA установлено успешно');
|
||||
document.getElementById('install-status').innerHTML =
|
||||
'<div class="success-message">✅ Приложение успешно установлено!</div>';
|
||||
|
||||
const installButton = document.getElementById('install-button');
|
||||
installButton.disabled = true;
|
||||
installButton.textContent = 'Приложение установлено';
|
||||
});
|
||||
|
||||
// Установка приложения
|
||||
document.getElementById('install-button').addEventListener('click', () => {
|
||||
if (deferredPrompt) {
|
||||
deferredPrompt.prompt();
|
||||
deferredPrompt.userChoice.then((choiceResult) => {
|
||||
console.log('Результат установки:', choiceResult.outcome);
|
||||
if (choiceResult.outcome === 'accepted') {
|
||||
document.getElementById('install-status').innerHTML =
|
||||
'<div class="success-message">✅ Пользователь принял установку</div>';
|
||||
} else {
|
||||
document.getElementById('install-status').innerHTML =
|
||||
'<div class="error-message">⚠️ Пользователь отклонил установку</div>';
|
||||
}
|
||||
deferredPrompt = null;
|
||||
});
|
||||
} else {
|
||||
document.getElementById('install-status').innerHTML =
|
||||
'<div class="error-message">❌ Установка недоступна. Попробуйте использовать меню браузера.</div>';
|
||||
}
|
||||
});
|
||||
|
||||
// Обновление ошибок консоли
|
||||
function updateConsoleErrors() {
|
||||
if (consoleErrors.length > 0) {
|
||||
document.getElementById('console-errors').textContent = consoleErrors.join('\n');
|
||||
} else {
|
||||
document.getElementById('console-errors').textContent = 'Нет ошибок';
|
||||
}
|
||||
}
|
||||
|
||||
// Инициализация
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
checkBasicRequirements();
|
||||
detailedDiagnostics();
|
||||
registerServiceWorker();
|
||||
|
||||
// Обновляем ошибки каждые 2 секунды
|
||||
setInterval(updateConsoleErrors, 2000);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -66,7 +66,11 @@ class PWAManager {
|
||||
console.log('beforeinstallprompt событие получено');
|
||||
e.preventDefault();
|
||||
this.deferredPrompt = e;
|
||||
this.showInstallButton();
|
||||
|
||||
// Показываем кнопку установки с задержкой для лучшего UX
|
||||
setTimeout(() => {
|
||||
this.showInstallButton();
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
@ -101,7 +105,8 @@ class PWAManager {
|
||||
const ua = navigator.userAgent;
|
||||
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua) ||
|
||||
(navigator.maxTouchPoints && navigator.maxTouchPoints > 2) ||
|
||||
window.matchMedia('(max-width: 768px)').matches;
|
||||
window.matchMedia('(max-width: 768px)').matches ||
|
||||
/Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
|
||||
}
|
||||
|
||||
// Проверка на мобильный Safari
|
||||
@ -178,6 +183,10 @@ class PWAManager {
|
||||
console.log('Результат установки:', choiceResult.outcome);
|
||||
if (choiceResult.outcome === 'accepted') {
|
||||
console.log('Пользователь установил приложение');
|
||||
this.showNotification('Приложение успешно установлено!', 'success');
|
||||
} else {
|
||||
console.log('Пользователь отклонил установку');
|
||||
this.showNotification('Установка отменена', 'warning');
|
||||
}
|
||||
this.deferredPrompt = null;
|
||||
this.removeInstallButton();
|
||||
@ -188,6 +197,41 @@ class PWAManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Принудительная проверка возможности установки
|
||||
async checkInstallability() {
|
||||
if (!this.isMobileDevice()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Проверяем все требования PWA
|
||||
const requirements = {
|
||||
hasManifest: document.querySelector('link[rel="manifest"]') !== null,
|
||||
hasServiceWorker: 'serviceWorker' in navigator,
|
||||
isSecure: location.protocol === 'https:' || location.hostname === 'localhost',
|
||||
hasIcons: document.querySelector('link[rel="icon"]') !== null
|
||||
};
|
||||
|
||||
const allRequirementsMet = Object.values(requirements).every(req => req);
|
||||
|
||||
if (!allRequirementsMet) {
|
||||
console.log('Не все требования PWA выполнены:', requirements);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Проверяем, есть ли deferredPrompt
|
||||
if (this.deferredPrompt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Для мобильных устройств без deferredPrompt показываем инструкции
|
||||
if (this.isMobileDevice()) {
|
||||
this.showMobileInstallInstructions();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Показать инструкции для Safari
|
||||
showSafariInstructions() {
|
||||
const instructions = `
|
||||
@ -210,6 +254,41 @@ class PWAManager {
|
||||
alert(instructions);
|
||||
}
|
||||
|
||||
// Показать инструкции для мобильных устройств
|
||||
showMobileInstallInstructions() {
|
||||
const isAndroid = /Android/i.test(navigator.userAgent);
|
||||
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
|
||||
|
||||
let instructions = '';
|
||||
|
||||
if (isAndroid) {
|
||||
instructions = `
|
||||
Для установки приложения на Android:
|
||||
1. Нажмите на меню браузера (⋮)
|
||||
2. Выберите "Установить приложение" или "Добавить на главный экран"
|
||||
3. Подтвердите установку
|
||||
|
||||
Или нажмите на иконку установки в адресной строке, если она появилась.
|
||||
`;
|
||||
} else if (isIOS) {
|
||||
instructions = `
|
||||
Для установки приложения на iOS:
|
||||
1. Нажмите кнопку "Поделиться" (□↗) внизу экрана
|
||||
2. Выберите "На экран Домой"
|
||||
3. Нажмите "Добавить"
|
||||
`;
|
||||
} else {
|
||||
instructions = `
|
||||
Для установки приложения:
|
||||
1. Откройте меню браузера
|
||||
2. Найдите "Установить приложение" или "Добавить на главный экран"
|
||||
3. Следуйте инструкциям браузера
|
||||
`;
|
||||
}
|
||||
|
||||
alert(instructions);
|
||||
}
|
||||
|
||||
// Удаление кнопки установки
|
||||
removeInstallButton() {
|
||||
const installButton = document.getElementById('pwa-install-button');
|
||||
@ -462,4 +541,18 @@ window.forceUpdate = async () => {
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
// Проверка возможности установки PWA
|
||||
window.checkInstallability = () => {
|
||||
return pwaManager.checkInstallability();
|
||||
};
|
||||
|
||||
// Принудительная попытка установки
|
||||
window.forceInstall = () => {
|
||||
if (pwaManager.isMobileDevice()) {
|
||||
pwaManager.showMobileInstallInstructions();
|
||||
} else {
|
||||
pwaManager.showManualInstallInstructions();
|
||||
}
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user