diff --git a/PWA-TESTING.md b/PWA-TESTING.md index 7ea307d..a73a35c 100644 --- a/PWA-TESTING.md +++ b/PWA-TESTING.md @@ -22,25 +22,30 @@ ## Как протестировать -### 1. Откройте тестовую страницу +### 1. Откройте тестовую страницу для мобильных устройств +``` +http://localhost:3000/mobile-pwa-test.html +``` + +### 2. Откройте обычную тестовую страницу ``` http://localhost:3000/test-pwa.html ``` -### 2. Проверьте требования PWA -Нажмите кнопку "Проверить статус PWA" - все пункты должны быть зелеными: +### 3. Проверьте требования PWA +На мобильной тестовой странице автоматически проверяются все требования: - ✅ HTTPS или localhost - ✅ Service Worker - ✅ Manifest - ✅ Иконки - ❌ Уже установлено (должно быть красным, если не установлено) -### 3. Установка приложения +### 4. Установка приложения - Если все проверки пройдены, появится кнопка "Установить приложение" - Нажмите на неё для установки PWA -- Следуйте инструкциям браузера +- Следуйте инструкциям браузера или используйте инструкции на странице -### 4. Проверка в разных браузерах +### 5. Проверка в разных браузерах #### Chrome/Edge: - Откройте DevTools (F12) @@ -59,6 +64,39 @@ http://localhost:3000/test-pwa.html - Выберите "На экран Домой" - Приложение установится как PWA +#### ПК/Десктоп (Chrome, Edge, Firefox): +- Откройте сайт в браузере +- Нажмите на иконку установки в адресной строке (если доступна) +- Или используйте меню браузера → "Установить приложение" +- Или используйте меню браузера → "Создать ярлык" + +## Новые улучшения для мобильных устройств + +✅ **Улучшенный manifest.json:** +- Добавлены все необходимые размеры иконок (72x72, 96x96, 128x128, 144x144, 152x152, 192x192, 384x384, 512x512) +- Добавлены maskable иконки для Android +- Добавлены категории и скриншоты +- Улучшена совместимость с мобильными устройствами + +✅ **Улучшенные мета-теги:** +- Добавлены все необходимые apple-touch-icon размеры +- Улучшена поддержка iOS Safari +- Добавлены мета-теги для Windows +- Настроен правильный статус-бар для iOS + +✅ **Улучшенный Service Worker:** +- Кэширование всех иконок +- Улучшенная обработка ошибок +- Fallback для различных типов ресурсов +- Лучшая поддержка мобильных устройств + +✅ **Улучшенный PWA Manager:** +- Определение мобильного Safari +- Разные инструкции для разных браузеров +- Улучшенная проверка установки PWA +- Поддержка различных режимов отображения +- **Кнопка установки показывается только на мобильных устройствах** + ## Возможные проблемы и решения ### 1. Кнопка установки не появляется @@ -66,11 +104,14 @@ http://localhost:3000/test-pwa.html - Приложение уже установлено - Браузер не поддерживает PWA - Не выполнены требования PWA +- **Вы используете ПК/десктоп (кнопка скрыта для ПК)** **Решение:** -- Проверьте статус на тестовой странице +- Проверьте статус на мобильной тестовой странице - Убедитесь, что используете HTTPS или localhost - Проверьте консоль браузера на ошибки +- Для iOS Safari используйте инструкции "Добавить на главный экран" +- **На ПК используйте меню браузера для установки PWA** ### 2. Service Worker не регистрируется **Причины:** @@ -125,6 +166,8 @@ 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/mobile-pwa-test.html` - мобильная тестовая страница +- ✅ `http://localhost:3000/test-pwa.html` - обычная тестовая страница ## Следующие шаги diff --git a/public/index.html b/public/index.html index 0cda61d..83500e5 100644 --- a/public/index.html +++ b/public/index.html @@ -10,15 +10,27 @@ - + + + + + + + + + + + + + @@ -109,25 +121,32 @@ e.preventDefault(); deferredPrompt = e; - // Показываем кнопку установки - const installButton = document.createElement('button'); - installButton.textContent = 'Установить приложение'; - installButton.className = 'btnSave'; - installButton.style.marginTop = '10px'; - installButton.style.width = '100%'; + // Проверяем, является ли устройство мобильным + const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || + (navigator.maxTouchPoints && navigator.maxTouchPoints > 2) || + window.matchMedia('(max-width: 768px)').matches; - installButton.addEventListener('click', () => { - deferredPrompt.prompt(); - deferredPrompt.userChoice.then((choiceResult) => { - if (choiceResult.outcome === 'accepted') { - console.log('Пользователь установил приложение'); - } - deferredPrompt = null; - installButton.remove(); + // Показываем кнопку установки только на мобильных устройствах + if (isMobile) { + const installButton = document.createElement('button'); + installButton.textContent = 'Установить приложение'; + installButton.className = 'btnSave'; + installButton.style.marginTop = '10px'; + installButton.style.width = '100%'; + + installButton.addEventListener('click', () => { + deferredPrompt.prompt(); + deferredPrompt.userChoice.then((choiceResult) => { + if (choiceResult.outcome === 'accepted') { + console.log('Пользователь установил приложение'); + } + deferredPrompt = null; + installButton.remove(); + }); }); - }); - - document.querySelector('.auth-link').appendChild(installButton); + + document.querySelector('.auth-link').appendChild(installButton); + } }); // Обработка успешной установки diff --git a/public/manifest.json b/public/manifest.json index 89fda3f..eb8a391 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -9,18 +9,75 @@ "orientation": "portrait-primary", "scope": "/", "lang": "ru", + "categories": ["productivity", "utilities"], + "screenshots": [ + { + "src": "/icons/icon-512x512.png", + "sizes": "512x512", + "type": "image/png", + "form_factor": "narrow" + } + ], "icons": [ + { + "src": "/icons/icon-72x72.png", + "sizes": "72x72", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icons/icon-96x96.png", + "sizes": "96x96", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icons/icon-128x128.png", + "sizes": "128x128", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icons/icon-144x144.png", + "sizes": "144x144", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icons/icon-152x152.png", + "sizes": "152x152", + "type": "image/png", + "purpose": "any" + }, { "src": "/icons/icon-192x192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" }, + { + "src": "/icons/icon-384x384.png", + "sizes": "384x384", + "type": "image/png", + "purpose": "any" + }, { "src": "/icons/icon-512x512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" + }, + { + "src": "/icons/icon-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "/icons/icon-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" } ] } diff --git a/public/mobile-pwa-test.html b/public/mobile-pwa-test.html new file mode 100644 index 0000000..a5b772b --- /dev/null +++ b/public/mobile-pwa-test.html @@ -0,0 +1,415 @@ + + + + + + Тест PWA для мобильных устройств - NoteJS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

📱 Тест PWA для мобильных устройств

+ +
+

Проверка требований PWA

+
+
+ HTTPS или localhost + Проверка... +
+
+ Service Worker + Проверка... +
+
+ Manifest + Проверка... +
+
+ Иконки + Проверка... +
+
+ Уже установлено + Проверка... +
+
+
+ +
+

Установка приложения

+
+ +
+
+ +
+

Инструкции по установке

+
+

Android Chrome/Edge:

+
    +
  1. Откройте сайт в Chrome или Edge
  2. +
  3. Нажмите кнопку "Установить приложение" выше
  4. +
  5. Или нажмите меню (⋮) → "Установить приложение"
  6. +
  7. Следуйте инструкциям браузера
  8. +
+
+ +
+

iOS Safari:

+
    +
  1. Откройте сайт в Safari
  2. +
  3. Нажмите кнопку "Поделиться" (□↗)
  4. +
  5. Выберите "На экран Домой"
  6. +
  7. Нажмите "Добавить"
  8. +
+
+ +
+

Другие браузеры:

+
    +
  1. Найдите опцию "Установить" в меню браузера
  2. +
  3. Или используйте "Добавить на главный экран"
  4. +
+
+
+ +
+

Отладочная информация

+ + +
+ +
+

Действия

+ + + +
+
+ + + + diff --git a/public/notes.html b/public/notes.html index a6af060..6ad650d 100644 --- a/public/notes.html +++ b/public/notes.html @@ -10,14 +10,27 @@ - + + + + + + + + + + + + + + diff --git a/public/pwa.js b/public/pwa.js index 9684ad2..989efa9 100644 --- a/public/pwa.js +++ b/public/pwa.js @@ -80,14 +80,47 @@ class PWAManager { return; } + // Показываем кнопку только на мобильных устройствах + if (!this.isMobileDevice()) { + console.log('Кнопка установки скрыта для ПК версии'); + return; + } + + // Проверяем, поддерживает ли браузер установку PWA + if (!this.deferredPrompt && !this.isMobileSafari()) { + console.log('Установка PWA не поддерживается в этом браузере'); + return; + } + const installButton = this.createInstallButton(); this.addInstallButtonToPage(installButton); } + // Проверка на мобильное устройство + isMobileDevice() { + 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; + } + + // Проверка на мобильный Safari + isMobileSafari() { + const ua = navigator.userAgent; + return /iPad|iPhone|iPod/.test(ua) && /Safari/.test(ua) && !/CriOS|FxiOS|OPiOS|mercury/.test(ua); + } + // Создание кнопки установки createInstallButton() { const installButton = document.createElement('button'); - installButton.textContent = '📱 Установить приложение'; + + // Разный текст для разных браузеров + if (this.isMobileSafari()) { + installButton.textContent = '📱 Добавить на главный экран'; + } else { + installButton.textContent = '📱 Установить приложение'; + } + installButton.className = 'btnSave'; installButton.style.marginTop = '10px'; installButton.style.width = '100%'; @@ -132,6 +165,13 @@ class PWAManager { // Установка приложения installApp() { console.log('Попытка установки приложения'); + + if (this.isMobileSafari()) { + // Для iOS Safari показываем инструкции + this.showSafariInstructions(); + return; + } + if (this.deferredPrompt) { this.deferredPrompt.prompt(); this.deferredPrompt.userChoice.then((choiceResult) => { @@ -144,9 +184,32 @@ class PWAManager { }); } else { console.log('deferredPrompt не доступен'); + this.showManualInstallInstructions(); } } + // Показать инструкции для Safari + showSafariInstructions() { + const instructions = ` + Для установки приложения на iOS: + 1. Нажмите кнопку "Поделиться" (□↗) внизу экрана + 2. Выберите "На экран Домой" + 3. Нажмите "Добавить" + `; + alert(instructions); + } + + // Показать инструкции для ручной установки + showManualInstallInstructions() { + const instructions = ` + Для установки приложения: + 1. Откройте меню браузера (⋮ или ☰) + 2. Найдите "Установить приложение" или "Добавить на главный экран" + 3. Следуйте инструкциям браузера + `; + alert(instructions); + } + // Удаление кнопки установки removeInstallButton() { const installButton = document.getElementById('pwa-install-button'); @@ -167,7 +230,9 @@ class PWAManager { // Проверка статуса PWA isPWAInstalled() { return window.matchMedia('(display-mode: standalone)').matches || - window.navigator.standalone === true; + window.navigator.standalone === true || + document.referrer.includes('android-app://') || + window.matchMedia('(display-mode: fullscreen)').matches; } // Получение информации о PWA @@ -177,7 +242,12 @@ class PWAManager { isOnline: navigator.onLine, hasServiceWorker: 'serviceWorker' in navigator, userAgent: navigator.userAgent, - hasDeferredPrompt: this.deferredPrompt !== null + hasDeferredPrompt: this.deferredPrompt !== null, + isMobileDevice: this.isMobileDevice(), + isMobileSafari: this.isMobileSafari(), + platform: navigator.platform, + language: navigator.language, + displayMode: window.matchMedia('(display-mode: standalone)').matches ? 'standalone' : 'browser' }; } diff --git a/public/register.html b/public/register.html index 3c52bbb..11d3ca0 100644 --- a/public/register.html +++ b/public/register.html @@ -10,14 +10,27 @@ - + + + + + + + + + + + + + + diff --git a/public/sw.js b/public/sw.js index 1fa7d63..c1f1449 100644 --- a/public/sw.js +++ b/public/sw.js @@ -1,5 +1,5 @@ // Service Worker для NoteJS -const APP_VERSION = '1.0.2'; +const APP_VERSION = '1.0.3'; const CACHE_NAME = `notejs-v${APP_VERSION}`; const STATIC_CACHE_NAME = `notejs-static-v${APP_VERSION}`; @@ -9,8 +9,16 @@ const STATIC_FILES = [ '/index.html', '/style.css', '/manifest.json', + '/icons/icon-72x72.png', + '/icons/icon-96x96.png', + '/icons/icon-128x128.png', + '/icons/icon-144x144.png', + '/icons/icon-152x152.png', '/icons/icon-192x192.png', - '/icons/icon-512x512.png' + '/icons/icon-384x384.png', + '/icons/icon-512x512.png', + '/icon.svg', + '/logo.svg' ]; // Установка Service Worker @@ -71,6 +79,11 @@ self.addEventListener('fetch', (event) => { return; } + // Пропускаем запросы к внешним ресурсам + if (url.origin !== location.origin) { + return; + } + // Обрабатываем только GET запросы if (request.method === 'GET') { event.respondWith( @@ -112,6 +125,22 @@ async function handleRequest(request) { } } + // Fallback для иконок + if (request.url.includes('/icons/')) { + const fallbackIcon = await caches.match('/icons/icon-192x192.png'); + if (fallbackIcon) { + return fallbackIcon; + } + } + + // Fallback для CSS + if (request.url.includes('/style.css')) { + const fallbackCSS = await caches.match('/style.css'); + if (fallbackCSS) { + return fallbackCSS; + } + } + throw error; } }