Обновлены файлы PWA и улучшена функциональность

- Добавлены новые мета-теги и улучшены существующие для поддержки PWA.
- Обновлен manifest.json с новыми полями для совместимости с Brave.
- Улучшен Service Worker для кэширования манифеста и обработки ошибок.
- Обновлены инструкции по тестированию PWA, включая новую тестовую страницу для Brave.
- Оптимизирован код для обработки установки PWA на мобильных устройствах и в Brave.
This commit is contained in:
Fovway 2025-10-20 12:35:29 +07:00
parent 091fc6cc1e
commit 02be77d790
5 changed files with 426 additions and 17 deletions

View File

@ -3,6 +3,7 @@
## Что было сделано
✅ **Созданы файлы PWA:**
- `manifest.json` - манифест приложения
- `sw.js` - сервис-воркер для кэширования
- `pwa.js` - JavaScript класс для управления PWA
@ -12,64 +13,88 @@
- `browserconfig.xml` - конфигурация для Windows
✅ **Обновлены HTML страницы:**
- Добавлены PWA мета-теги
- Подключены иконки и манифест
- Добавлен скрипт регистрации Service Worker
✅ **Настроен сервер:**
- Правильные заголовки для PWA файлов
- Поддержка кэширования
## Как протестировать
### 1. Откройте диагностическую страницу PWA
```
http://localhost:3000/pwa-debug.html
```
### 2. Откройте тестовую страницу для мобильных устройств
```
http://localhost:3000/mobile-pwa-test.html
```
### 3. Откройте обычную тестовую страницу
### 3. Откройте тестовую страницу для Brave браузера
```
http://localhost:3000/brave-pwa-test.html
```
### 4. Откройте обычную тестовую страницу
```
http://localhost:3000/test-pwa.html
```
### 4. Проверьте требования PWA
### 5. Проверьте требования PWA
На мобильной тестовой странице автоматически проверяются все требования:
- ✅ HTTPS или localhost
- ✅ Service Worker
- ✅ Manifest
- ✅ Иконки
- ❌ Уже установлено (должно быть красным, если не установлено)
### 5. Установка приложения
### 6. Установка приложения
- Если все проверки пройдены, появится кнопка "Установить приложение"
- Нажмите на неё для установки PWA
- Следуйте инструкциям браузера или используйте инструкции на странице
### 6. Проверка в разных браузерах
### 7. Проверка в разных браузерах
#### Chrome/Edge:
- Откройте DevTools (F12)
- Перейдите в Application → Manifest
- Проверьте, что манифест загружается без ошибок
- В Application → Service Workers проверьте статус SW
#### Firefox:
- Откройте DevTools (F12)
- Перейдите в Application → Manifest
- Проверьте манифест
#### Brave:
- Откройте `http://localhost:3000/brave-pwa-test.html` для диагностики
- Проверьте настройки PWA в браузере
- Используйте меню браузера для установки
#### Safari (iOS):
- Откройте сайт в Safari
- Нажмите кнопку "Поделиться"
- Выберите "На экран Домой"
- Приложение установится как PWA
#### ПК/Десктоп (Chrome, Edge, Firefox):
- Откройте сайт в браузере
- Нажмите на иконку установки в адресной строке (если доступна)
- Или используйте меню браузера → "Установить приложение"
@ -78,24 +103,28 @@ http://localhost:3000/test-pwa.html
## Новые улучшения для мобильных устройств
✅ **Улучшенный 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
@ -108,51 +137,83 @@ http://localhost:3000/test-pwa.html
## Возможные проблемы и решения
### 1. Кнопка установки не появляется
**Причины:**
- Приложение уже установлено
- Браузер не поддерживает PWA
- Не выполнены требования PWA
- **Вы используете ПК/десктоп (кнопка скрыта для ПК)**
- **Проблемы с Brave браузером**
**Решение:**
- Проверьте статус на мобильной тестовой странице
- Убедитесь, что используете HTTPS или localhost
- Проверьте консоль браузера на ошибки
- Для iOS Safari используйте инструкции "Добавить на главный экран"
- **На ПК используйте меню браузера для установки PWA**
- **Для Brave: проверьте настройки PWA в браузере**
### 1.1. Проблемы с Brave браузером
**Причины:**
- Brave может блокировать PWA по умолчанию
- Неправильная конфигурация manifest.json
- Проблемы с Service Worker в Brave
**Решение:**
- Откройте `http://localhost:3000/brave-pwa-test.html` для диагностики
- В Brave перейдите в **Настройки → Дополнительно → Сайты и разрешения → PWA**
- Убедитесь, что PWA включены
- Попробуйте установить через меню браузера (три точки → "Установить приложение")
- Обновите manifest.json с новыми полями для Brave совместимости
### 2. Service Worker не регистрируется
**Причины:**
- Ошибки в коде SW
- Проблемы с кэшированием файлов
**Решение:**
- Откройте DevTools → Application → Service Workers
- Проверьте ошибки в консоли
- Попробуйте очистить кэш
### 3. Ошибка "Download error or resource isn't a valid image"
**Причины:**
- PNG иконки повреждены или имеют неправильный размер
- Иконки не являются валидными PNG файлами
**Решение:**
- ✅ **ИСПРАВЛЕНО**: Созданы правильные PNG иконки с помощью pngjs
- Проверьте, что иконки имеют правильные размеры (192x192, 512x512)
- Убедитесь, что файлы иконок валидные PNG
### 4. Предупреждение о deprecated meta tag
**Причины:**
- Использование устаревшего `apple-mobile-web-app-capable`
**Решение:**
- ✅ **ИСПРАВЛЕНО**: Добавлен современный `mobile-web-app-capable`
- Оба тега теперь присутствуют для совместимости
## Отладка
### Консоль браузера
Откройте DevTools (F12) и проверьте консоль на ошибки:
```javascript
// Проверить статус PWA
window.debugPWA();
@ -168,7 +229,9 @@ window.forceInstall();
```
### Диагностическая страница
Используйте `http://localhost:3000/pwa-debug.html` для:
- Детальной диагностики всех требований PWA
- Проверки загрузки манифеста и Service Worker
- Отображения информации о браузере и устройстве
@ -176,7 +239,9 @@ window.forceInstall();
- Тестирования установки PWA
### Lighthouse
Запустите аудит Lighthouse в Chrome DevTools:
1. Откройте DevTools (F12)
2. Перейдите в Lighthouse
3. Выберите "Progressive Web App"
@ -190,11 +255,13 @@ window.forceInstall();
- ✅ `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/brave-pwa-test.html` - тестовая страница для Brave браузера
- ✅ `http://localhost:3000/test-pwa.html` - обычная тестовая страница
## Следующие шаги
После успешного тестирования:
1. Удалите тестовую страницу `test-pwa.html`
2. Настройте HTTPS для продакшена
3. Добавьте реальные скриншоты в манифест

333
public/brave-pwa-test.html Normal file
View File

@ -0,0 +1,333 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Тест PWA для Brave - NoteJS</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
line-height: 1.6;
}
.status {
padding: 10px;
margin: 10px 0;
border-radius: 5px;
border-left: 4px solid;
}
.success {
background: #d4edda;
border-color: #28a745;
color: #155724;
}
.error {
background: #f8d7da;
border-color: #dc3545;
color: #721c24;
}
.warning {
background: #fff3cd;
border-color: #ffc107;
color: #856404;
}
.info {
background: #d1ecf1;
border-color: #17a2b8;
color: #0c5460;
}
button {
background: #007bff;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
margin: 5px;
}
button:hover {
background: #0056b3;
}
button:disabled {
background: #6c757d;
cursor: not-allowed;
}
.test-section {
margin: 20px 0;
padding: 15px;
border: 1px solid #ddd;
border-radius: 5px;
}
.browser-info {
background: #f8f9fa;
padding: 15px;
border-radius: 5px;
margin: 10px 0;
}
</style>
</head>
<body>
<h1>🔍 Диагностика PWA для Brave браузера</h1>
<div class="browser-info">
<h3>Информация о браузере:</h3>
<div id="browserInfo"></div>
</div>
<div class="test-section">
<h2>📋 Проверка требований PWA</h2>
<div id="pwaRequirements"></div>
</div>
<div class="test-section">
<h2>🔧 Тестирование установки</h2>
<button id="installBtn" style="display: none">
Установить приложение
</button>
<button id="checkInstallBtn">Проверить возможность установки</button>
<div id="installStatus"></div>
</div>
<div class="test-section">
<h2>📱 Инструкции для Brave</h2>
<div id="braveInstructions"></div>
</div>
<div class="test-section">
<h2>🐛 Отладочная информация</h2>
<button id="debugBtn">Показать отладочную информацию</button>
<div id="debugInfo" style="display: none"></div>
</div>
<script>
let deferredPrompt;
let isBrave = false;
// Определяем браузер
function detectBrowser() {
const userAgent = navigator.userAgent;
isBrave =
userAgent.includes("Brave") ||
(navigator.brave && navigator.brave.isBrave);
const browserInfo = document.getElementById("browserInfo");
browserInfo.innerHTML = `
<p><strong>User Agent:</strong> ${userAgent}</p>
<p><strong>Браузер:</strong> ${isBrave ? "Brave" : "Другой"}</p>
<p><strong>Платформа:</strong> ${navigator.platform}</p>
<p><strong>Мобильное устройство:</strong> ${
isMobile() ? "Да" : "Нет"
}</p>
<p><strong>HTTPS:</strong> ${
location.protocol === "https:" ? "Да" : "Нет"
}</p>
<p><strong>Localhost:</strong> ${
location.hostname === "localhost" ? "Да" : "Нет"
}</p>
`;
}
function isMobile() {
return (
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
) ||
(navigator.maxTouchPoints && navigator.maxTouchPoints > 2) ||
window.matchMedia("(max-width: 768px)").matches
);
}
// Проверка требований PWA
function checkPWARequirements() {
const requirements = document.getElementById("pwaRequirements");
let html = "";
// HTTPS или localhost
const isSecure =
location.protocol === "https:" || location.hostname === "localhost";
html += `<div class="status ${isSecure ? "success" : "error"}">
${isSecure ? "✅" : "❌"} HTTPS или localhost: ${
isSecure ? "Да" : "Нет"
}
</div>`;
// Service Worker
const hasSW = "serviceWorker" in navigator;
html += `<div class="status ${hasSW ? "success" : "error"}">
${hasSW ? "✅" : "❌"} Service Worker API: ${
hasSW ? "Поддерживается" : "Не поддерживается"
}
</div>`;
// Manifest
fetch("/manifest.json")
.then((response) => response.ok)
.then((manifestOk) => {
html += `<div class="status ${manifestOk ? "success" : "error"}">
${manifestOk ? "✅" : "❌"} Manifest.json: ${
manifestOk ? "Загружается" : "Ошибка загрузки"
}
</div>`;
requirements.innerHTML = html;
})
.catch(() => {
html += `<div class="status error">
❌ Manifest.json: Ошибка загрузки
</div>`;
requirements.innerHTML = html;
});
// Иконки
fetch("/icons/icon-192x192.png")
.then((response) => response.ok)
.then((iconOk) => {
html += `<div class="status ${iconOk ? "success" : "error"}">
${iconOk ? "✅" : "❌"} Иконки: ${
iconOk ? "Доступны" : "Не найдены"
}
</div>`;
requirements.innerHTML = html;
})
.catch(() => {
html += `<div class="status error">
❌ Иконки: Не найдены
</div>`;
requirements.innerHTML = html;
});
}
// Проверка возможности установки
function checkInstallability() {
const status = document.getElementById("installStatus");
status.innerHTML =
'<div class="status info">Проверяем возможность установки...</div>';
// Проверяем, установлено ли уже приложение
if (
window.matchMedia("(display-mode: standalone)").matches ||
window.navigator.standalone === true
) {
status.innerHTML =
'<div class="status warning">⚠️ Приложение уже установлено</div>';
return;
}
// Проверяем beforeinstallprompt
if (deferredPrompt) {
status.innerHTML =
'<div class="status success">✅ Приложение можно установить</div>';
document.getElementById("installBtn").style.display = "inline-block";
} else {
status.innerHTML =
'<div class="status warning">⚠️ Событие beforeinstallprompt не сработало</div>';
}
}
// Инструкции для Brave
function showBraveInstructions() {
const instructions = document.getElementById("braveInstructions");
let html = "";
if (isBrave) {
html += `
<div class="status info">
<h4>Инструкции для Brave браузера:</h4>
<ol>
<li>Убедитесь, что у вас включены PWA в настройках Brave</li>
<li>Перейдите в <strong>Настройки → Дополнительно → Сайты и разрешения → PWA</strong></li>
<li>Убедитесь, что PWA включены</li>
<li>Попробуйте установить приложение через меню браузера</li>
</ol>
</div>
`;
}
html += `
<div class="status info">
<h4>Общие инструкции для установки PWA:</h4>
<ul>
<li><strong>Android:</strong> Нажмите на меню браузера (три точки) → "Установить приложение"</li>
<li><strong>iOS:</strong> Нажмите кнопку "Поделиться" → "На экран Домой"</li>
<li><strong>Desktop:</strong> Нажмите на иконку установки в адресной строке</li>
</ul>
</div>
`;
instructions.innerHTML = html;
}
// Отладочная информация
function showDebugInfo() {
const debugInfo = document.getElementById("debugInfo");
debugInfo.style.display =
debugInfo.style.display === "none" ? "block" : "none";
if (debugInfo.style.display === "block") {
debugInfo.innerHTML = `
<h4>Отладочная информация:</h4>
<pre>${JSON.stringify(
{
userAgent: navigator.userAgent,
isBrave: isBrave,
isMobile: isMobile(),
protocol: location.protocol,
hostname: location.hostname,
standalone: window.navigator.standalone,
displayMode: window.matchMedia(
"(display-mode: standalone)"
).matches,
serviceWorker: "serviceWorker" in navigator,
beforeinstallprompt: !!deferredPrompt,
},
null,
2
)}</pre>
`;
}
}
// Обработчики событий
window.addEventListener("beforeinstallprompt", (e) => {
console.log("beforeinstallprompt event fired");
e.preventDefault();
deferredPrompt = e;
checkInstallability();
});
window.addEventListener("appinstalled", () => {
console.log("PWA installed successfully");
document.getElementById("installStatus").innerHTML =
'<div class="status success">✅ Приложение успешно установлено!</div>';
});
// Инициализация
document.addEventListener("DOMContentLoaded", () => {
detectBrowser();
checkPWARequirements();
showBraveInstructions();
document
.getElementById("checkInstallBtn")
.addEventListener("click", checkInstallability);
document
.getElementById("installBtn")
.addEventListener("click", async () => {
if (deferredPrompt) {
deferredPrompt.prompt();
const choiceResult = await deferredPrompt.userChoice;
if (choiceResult.outcome === "accepted") {
console.log("User accepted the install prompt");
}
deferredPrompt = null;
}
});
document
.getElementById("debugBtn")
.addEventListener("click", showDebugInfo);
});
</script>
</body>
</html>

View File

@ -160,7 +160,11 @@
// Обработка установки PWA
let deferredPrompt;
window.addEventListener("beforeinstallprompt", (e) => {
// На мобильных устройствах позволяем браузеру показать нативный баннер
console.log("beforeinstallprompt event fired");
// Определяем браузер
const isBrave = navigator.userAgent.includes('Brave') ||
(navigator.brave && await navigator.brave.isBrave());
const isMobile =
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
@ -168,28 +172,30 @@
(navigator.maxTouchPoints && navigator.maxTouchPoints > 2) ||
window.matchMedia("(max-width: 768px)").matches;
if (!isMobile) {
// Для Brave на мобильных устройствах не предотвращаем стандартное поведение
if (!isMobile && !isBrave) {
e.preventDefault();
}
deferredPrompt = e;
// Показываем кнопку установки только на мобильных устройствах
if (isMobile) {
// Показываем кнопку установки на мобильных устройствах или в Brave
if (isMobile || isBrave) {
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) => {
installButton.addEventListener("click", async () => {
if (deferredPrompt) {
deferredPrompt.prompt();
const choiceResult = await deferredPrompt.userChoice;
if (choiceResult.outcome === "accepted") {
console.log("Пользователь установил приложение");
}
deferredPrompt = null;
installButton.remove();
});
}
});
document.querySelector(".auth-link").appendChild(installButton);

View File

@ -11,6 +11,8 @@
"lang": "ru",
"id": "/",
"categories": ["productivity", "utilities"],
"prefer_related_applications": false,
"display_override": ["window-controls-overlay", "standalone"],
"screenshots": [
{
"src": "/icons/icon-512x512.png",

View File

@ -1,11 +1,11 @@
// Service Worker для NoteJS
const APP_VERSION = "1.0.5";
const APP_VERSION = "1.0.6";
const CACHE_NAME = `notejs-v${APP_VERSION}`;
const STATIC_CACHE_NAME = `notejs-static-v${APP_VERSION}`;
// Файлы для кэширования при установке (только изображения, иконки, логотипы)
// Манифест убран - не нужен для офлайн работы
// Файлы для кэширования при установке (включая манифест для Brave)
const STATIC_FILES = [
"/manifest.json",
"/icons/icon-72x72.png",
"/icons/icon-96x96.png",
"/icons/icon-128x128.png",
@ -141,7 +141,7 @@ async function handleRequest(request) {
function shouldCache(request) {
const url = new URL(request.url);
// Кэшируем только изображения, иконки и логотипы (без манифеста для офлайн работы)
// Кэшируем изображения, иконки, логотипы и манифест (для Brave совместимости)
return (
url.pathname.includes("/icons/") ||
url.pathname.endsWith(".png") ||
@ -149,7 +149,8 @@ function shouldCache(request) {
url.pathname.endsWith(".jpeg") ||
url.pathname.endsWith(".gif") ||
url.pathname.endsWith(".webp") ||
url.pathname.endsWith(".svg")
url.pathname.endsWith(".svg") ||
url.pathname.endsWith("manifest.json")
);
}