✨ Улучшена поддержка PWA и мобильных устройств
- Обновлены инструкции по тестированию PWA для мобильных и десктопных устройств. - Добавлены новые мета-теги и улучшены иконки для поддержки iOS и Windows. - Оптимизирован Service Worker для кэширования и обработки ошибок. - Реализована кнопка установки, отображающаяся только на мобильных устройствах, с различными инструкциями для разных браузеров. - Обновлен manifest.json с добавлением категорий и скриншотов.
This commit is contained in:
parent
fbc2b5259c
commit
95401328c4
@ -22,25 +22,30 @@
|
|||||||
|
|
||||||
## Как протестировать
|
## Как протестировать
|
||||||
|
|
||||||
### 1. Откройте тестовую страницу
|
### 1. Откройте тестовую страницу для мобильных устройств
|
||||||
|
```
|
||||||
|
http://localhost:3000/mobile-pwa-test.html
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Откройте обычную тестовую страницу
|
||||||
```
|
```
|
||||||
http://localhost:3000/test-pwa.html
|
http://localhost:3000/test-pwa.html
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Проверьте требования PWA
|
### 3. Проверьте требования PWA
|
||||||
Нажмите кнопку "Проверить статус PWA" - все пункты должны быть зелеными:
|
На мобильной тестовой странице автоматически проверяются все требования:
|
||||||
- ✅ HTTPS или localhost
|
- ✅ HTTPS или localhost
|
||||||
- ✅ Service Worker
|
- ✅ Service Worker
|
||||||
- ✅ Manifest
|
- ✅ Manifest
|
||||||
- ✅ Иконки
|
- ✅ Иконки
|
||||||
- ❌ Уже установлено (должно быть красным, если не установлено)
|
- ❌ Уже установлено (должно быть красным, если не установлено)
|
||||||
|
|
||||||
### 3. Установка приложения
|
### 4. Установка приложения
|
||||||
- Если все проверки пройдены, появится кнопка "Установить приложение"
|
- Если все проверки пройдены, появится кнопка "Установить приложение"
|
||||||
- Нажмите на неё для установки PWA
|
- Нажмите на неё для установки PWA
|
||||||
- Следуйте инструкциям браузера
|
- Следуйте инструкциям браузера или используйте инструкции на странице
|
||||||
|
|
||||||
### 4. Проверка в разных браузерах
|
### 5. Проверка в разных браузерах
|
||||||
|
|
||||||
#### Chrome/Edge:
|
#### Chrome/Edge:
|
||||||
- Откройте DevTools (F12)
|
- Откройте DevTools (F12)
|
||||||
@ -59,6 +64,39 @@ http://localhost:3000/test-pwa.html
|
|||||||
- Выберите "На экран Домой"
|
- Выберите "На экран Домой"
|
||||||
- Приложение установится как PWA
|
- Приложение установится как 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. Кнопка установки не появляется
|
### 1. Кнопка установки не появляется
|
||||||
@ -66,11 +104,14 @@ http://localhost:3000/test-pwa.html
|
|||||||
- Приложение уже установлено
|
- Приложение уже установлено
|
||||||
- Браузер не поддерживает PWA
|
- Браузер не поддерживает PWA
|
||||||
- Не выполнены требования PWA
|
- Не выполнены требования PWA
|
||||||
|
- **Вы используете ПК/десктоп (кнопка скрыта для ПК)**
|
||||||
|
|
||||||
**Решение:**
|
**Решение:**
|
||||||
- Проверьте статус на тестовой странице
|
- Проверьте статус на мобильной тестовой странице
|
||||||
- Убедитесь, что используете HTTPS или localhost
|
- Убедитесь, что используете HTTPS или localhost
|
||||||
- Проверьте консоль браузера на ошибки
|
- Проверьте консоль браузера на ошибки
|
||||||
|
- Для iOS Safari используйте инструкции "Добавить на главный экран"
|
||||||
|
- **На ПК используйте меню браузера для установки PWA**
|
||||||
|
|
||||||
### 2. Service Worker не регистрируется
|
### 2. Service Worker не регистрируется
|
||||||
**Причины:**
|
**Причины:**
|
||||||
@ -125,6 +166,8 @@ navigator.serviceWorker.getRegistrations().then(console.log);
|
|||||||
- ✅ `http://localhost:3000/sw.js` - должен возвращать JavaScript
|
- ✅ `http://localhost:3000/sw.js` - должен возвращать JavaScript
|
||||||
- ✅ `http://localhost:3000/icons/icon-192x192.png` - должен возвращать PNG
|
- ✅ `http://localhost:3000/icons/icon-192x192.png` - должен возвращать PNG
|
||||||
- ✅ `http://localhost:3000/icons/icon-512x512.png` - должен возвращать PNG
|
- ✅ `http://localhost:3000/icons/icon-512x512.png` - должен возвращать PNG
|
||||||
|
- ✅ `http://localhost:3000/mobile-pwa-test.html` - мобильная тестовая страница
|
||||||
|
- ✅ `http://localhost:3000/test-pwa.html` - обычная тестовая страница
|
||||||
|
|
||||||
## Следующие шаги
|
## Следующие шаги
|
||||||
|
|
||||||
|
|||||||
@ -10,15 +10,27 @@
|
|||||||
<meta name="theme-color" content="#007bff" />
|
<meta name="theme-color" content="#007bff" />
|
||||||
<meta name="mobile-web-app-capable" content="yes" />
|
<meta name="mobile-web-app-capable" content="yes" />
|
||||||
<meta name="apple-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="default" />
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||||
<meta name="apple-mobile-web-app-title" content="NoteJS" />
|
<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-TileColor" content="#007bff" />
|
||||||
<meta name="msapplication-config" content="/browserconfig.xml" />
|
<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 -->
|
<!-- Icons -->
|
||||||
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
<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="32x32" href="/icons/icon-32x32.png" />
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/icons/icon-16x16.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="apple-touch-icon" sizes="180x180" href="/icons/icon-192x192.png" />
|
||||||
<link rel="mask-icon" href="/icon.svg" color="#007bff" />
|
<link rel="mask-icon" href="/icon.svg" color="#007bff" />
|
||||||
|
|
||||||
@ -109,7 +121,13 @@
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
deferredPrompt = e;
|
deferredPrompt = e;
|
||||||
|
|
||||||
// Показываем кнопку установки
|
// Проверяем, является ли устройство мобильным
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Показываем кнопку установки только на мобильных устройствах
|
||||||
|
if (isMobile) {
|
||||||
const installButton = document.createElement('button');
|
const installButton = document.createElement('button');
|
||||||
installButton.textContent = 'Установить приложение';
|
installButton.textContent = 'Установить приложение';
|
||||||
installButton.className = 'btnSave';
|
installButton.className = 'btnSave';
|
||||||
@ -128,6 +146,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector('.auth-link').appendChild(installButton);
|
document.querySelector('.auth-link').appendChild(installButton);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Обработка успешной установки
|
// Обработка успешной установки
|
||||||
|
|||||||
@ -9,18 +9,75 @@
|
|||||||
"orientation": "portrait-primary",
|
"orientation": "portrait-primary",
|
||||||
"scope": "/",
|
"scope": "/",
|
||||||
"lang": "ru",
|
"lang": "ru",
|
||||||
|
"categories": ["productivity", "utilities"],
|
||||||
|
"screenshots": [
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"form_factor": "narrow"
|
||||||
|
}
|
||||||
|
],
|
||||||
"icons": [
|
"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",
|
"src": "/icons/icon-192x192.png",
|
||||||
"sizes": "192x192",
|
"sizes": "192x192",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"purpose": "any"
|
"purpose": "any"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-384x384.png",
|
||||||
|
"sizes": "384x384",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "any"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"src": "/icons/icon-512x512.png",
|
"src": "/icons/icon-512x512.png",
|
||||||
"sizes": "512x512",
|
"sizes": "512x512",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"purpose": "any"
|
"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"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
415
public/mobile-pwa-test.html
Normal file
415
public/mobile-pwa-test.html
Normal file
@ -0,0 +1,415 @@
|
|||||||
|
<!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 на мобильных устройствах" />
|
||||||
|
<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>
|
||||||
|
.test-container {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.test-section {
|
||||||
|
background: #f8f9fa;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.test-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 0;
|
||||||
|
border-bottom: 1px solid #e9ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.test-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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instructions {
|
||||||
|
background: #e7f3ff;
|
||||||
|
border: 1px solid #b3d9ff;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instructions h4 {
|
||||||
|
margin-top: 0;
|
||||||
|
color: #0066cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instructions ol {
|
||||||
|
margin: 10px 0;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instructions li {
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-info {
|
||||||
|
background: #f8f9fa;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 10px;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="test-container">
|
||||||
|
<h1>📱 Тест PWA для мобильных устройств</h1>
|
||||||
|
|
||||||
|
<div class="test-section">
|
||||||
|
<h3>Проверка требований PWA</h3>
|
||||||
|
<div id="pwa-checks">
|
||||||
|
<div class="test-item">
|
||||||
|
<span>HTTPS или localhost</span>
|
||||||
|
<span class="status" id="https-check">Проверка...</span>
|
||||||
|
</div>
|
||||||
|
<div class="test-item">
|
||||||
|
<span>Service Worker</span>
|
||||||
|
<span class="status" id="sw-check">Проверка...</span>
|
||||||
|
</div>
|
||||||
|
<div class="test-item">
|
||||||
|
<span>Manifest</span>
|
||||||
|
<span class="status" id="manifest-check">Проверка...</span>
|
||||||
|
</div>
|
||||||
|
<div class="test-item">
|
||||||
|
<span>Иконки</span>
|
||||||
|
<span class="status" id="icons-check">Проверка...</span>
|
||||||
|
</div>
|
||||||
|
<div class="test-item">
|
||||||
|
<span>Уже установлено</span>
|
||||||
|
<span class="status" id="installed-check">Проверка...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="test-section">
|
||||||
|
<h3>Установка приложения</h3>
|
||||||
|
<div id="device-info" style="margin-bottom: 10px; padding: 10px; background: #e7f3ff; border-radius: 4px; font-size: 14px;"></div>
|
||||||
|
<button id="install-button" class="install-button" disabled>
|
||||||
|
Установить приложение
|
||||||
|
</button>
|
||||||
|
<div id="install-status"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="test-section">
|
||||||
|
<h3>Инструкции по установке</h3>
|
||||||
|
<div class="instructions">
|
||||||
|
<h4>Android Chrome/Edge:</h4>
|
||||||
|
<ol>
|
||||||
|
<li>Откройте сайт в Chrome или Edge</li>
|
||||||
|
<li>Нажмите кнопку "Установить приложение" выше</li>
|
||||||
|
<li>Или нажмите меню (⋮) → "Установить приложение"</li>
|
||||||
|
<li>Следуйте инструкциям браузера</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="instructions">
|
||||||
|
<h4>iOS Safari:</h4>
|
||||||
|
<ol>
|
||||||
|
<li>Откройте сайт в Safari</li>
|
||||||
|
<li>Нажмите кнопку "Поделиться" (□↗)</li>
|
||||||
|
<li>Выберите "На экран Домой"</li>
|
||||||
|
<li>Нажмите "Добавить"</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="instructions">
|
||||||
|
<h4>Другие браузеры:</h4>
|
||||||
|
<ol>
|
||||||
|
<li>Найдите опцию "Установить" в меню браузера</li>
|
||||||
|
<li>Или используйте "Добавить на главный экран"</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="test-section">
|
||||||
|
<h3>Отладочная информация</h3>
|
||||||
|
<button onclick="showDebugInfo()" class="install-button">Показать отладочную информацию</button>
|
||||||
|
<div id="debug-info" class="debug-info" style="display: none;"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="test-section">
|
||||||
|
<h3>Действия</h3>
|
||||||
|
<button onclick="clearCache()" class="install-button">Очистить кэш</button>
|
||||||
|
<button onclick="forceUpdate()" class="install-button">Принудительное обновление</button>
|
||||||
|
<button onclick="location.reload()" class="install-button">Перезагрузить страницу</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let deferredPrompt;
|
||||||
|
|
||||||
|
// Проверка требований PWA
|
||||||
|
function checkPWARequirements() {
|
||||||
|
// 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'}`;
|
||||||
|
|
||||||
|
// Уже установлено
|
||||||
|
const isInstalled = window.matchMedia('(display-mode: standalone)').matches ||
|
||||||
|
window.navigator.standalone === true;
|
||||||
|
document.getElementById('installed-check').textContent = isInstalled ? '✅ Да' : '❌ Нет';
|
||||||
|
document.getElementById('installed-check').className = `status ${isInstalled ? 'warning' : 'pass'}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Регистрация 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;
|
||||||
|
|
||||||
|
// Проверяем, является ли устройство мобильным
|
||||||
|
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;
|
||||||
|
|
||||||
|
const installButton = document.getElementById('install-button');
|
||||||
|
if (isMobile) {
|
||||||
|
installButton.disabled = false;
|
||||||
|
installButton.textContent = '📱 Установить приложение';
|
||||||
|
} else {
|
||||||
|
installButton.disabled = true;
|
||||||
|
installButton.textContent = '💻 Установка доступна через меню браузера';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Обработка успешной установки
|
||||||
|
window.addEventListener('appinstalled', () => {
|
||||||
|
console.log('PWA установлено успешно');
|
||||||
|
document.getElementById('install-status').innerHTML =
|
||||||
|
'<div style="color: green; margin-top: 10px;">✅ Приложение успешно установлено!</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 style="color: green; margin-top: 10px;">✅ Пользователь принял установку</div>';
|
||||||
|
} else {
|
||||||
|
document.getElementById('install-status').innerHTML =
|
||||||
|
'<div style="color: orange; margin-top: 10px;">⚠️ Пользователь отклонил установку</div>';
|
||||||
|
}
|
||||||
|
deferredPrompt = null;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
document.getElementById('install-status').innerHTML =
|
||||||
|
'<div style="color: red; margin-top: 10px;">❌ Установка недоступна. Попробуйте использовать меню браузера.</div>';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Показать отладочную информацию
|
||||||
|
function showDebugInfo() {
|
||||||
|
const debugInfo = document.getElementById('debug-info');
|
||||||
|
const info = {
|
||||||
|
userAgent: navigator.userAgent,
|
||||||
|
platform: navigator.platform,
|
||||||
|
language: navigator.language,
|
||||||
|
onLine: navigator.onLine,
|
||||||
|
cookieEnabled: navigator.cookieEnabled,
|
||||||
|
displayMode: window.matchMedia('(display-mode: standalone)').matches ? 'standalone' : 'browser',
|
||||||
|
standalone: window.navigator.standalone,
|
||||||
|
hasServiceWorker: 'serviceWorker' in navigator,
|
||||||
|
hasDeferredPrompt: deferredPrompt !== null,
|
||||||
|
location: {
|
||||||
|
href: location.href,
|
||||||
|
protocol: location.protocol,
|
||||||
|
hostname: location.hostname,
|
||||||
|
port: location.port
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
debugInfo.textContent = JSON.stringify(info, null, 2);
|
||||||
|
debugInfo.style.display = debugInfo.style.display === 'none' ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Очистка кэша
|
||||||
|
async function clearCache() {
|
||||||
|
if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
|
||||||
|
try {
|
||||||
|
navigator.serviceWorker.controller.postMessage({
|
||||||
|
type: 'CLEAR_ALL_CACHE'
|
||||||
|
});
|
||||||
|
alert('Запрос на очистку кэша отправлен');
|
||||||
|
} catch (error) {
|
||||||
|
alert('Ошибка при очистке кэша: ' + error.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert('Service Worker не доступен');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Принудительное обновление
|
||||||
|
async function forceUpdate() {
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
try {
|
||||||
|
const registration = await navigator.serviceWorker.getRegistration();
|
||||||
|
if (registration) {
|
||||||
|
await registration.update();
|
||||||
|
alert('Проверка обновлений завершена');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert('Ошибка при проверке обновлений: ' + error.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert('Service Worker не поддерживается');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверка типа устройства
|
||||||
|
function checkDeviceType() {
|
||||||
|
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;
|
||||||
|
|
||||||
|
const deviceInfo = document.getElementById('device-info');
|
||||||
|
if (isMobile) {
|
||||||
|
deviceInfo.innerHTML = '📱 <strong>Мобильное устройство</strong> - кнопка установки доступна';
|
||||||
|
deviceInfo.style.background = '#d4edda';
|
||||||
|
deviceInfo.style.color = '#155724';
|
||||||
|
} else {
|
||||||
|
deviceInfo.innerHTML = '💻 <strong>ПК/Десктоп</strong> - кнопка установки скрыта (PWA доступно через меню браузера)';
|
||||||
|
deviceInfo.style.background = '#fff3cd';
|
||||||
|
deviceInfo.style.color = '#856404';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Инициализация
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
checkDeviceType();
|
||||||
|
checkPWARequirements();
|
||||||
|
registerServiceWorker();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -10,14 +10,27 @@
|
|||||||
<meta name="theme-color" content="#007bff" />
|
<meta name="theme-color" content="#007bff" />
|
||||||
<meta name="mobile-web-app-capable" content="yes" />
|
<meta name="mobile-web-app-capable" content="yes" />
|
||||||
<meta name="apple-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="default" />
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||||
<meta name="apple-mobile-web-app-title" content="NoteJS" />
|
<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-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 -->
|
<!-- Icons -->
|
||||||
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
<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="32x32" href="/icons/icon-32x32.png" />
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/icons/icon-16x16.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="apple-touch-icon" sizes="180x180" href="/icons/icon-192x192.png" />
|
||||||
<link rel="mask-icon" href="/icon.svg" color="#007bff" />
|
<link rel="mask-icon" href="/icon.svg" color="#007bff" />
|
||||||
|
|
||||||
|
|||||||
@ -80,14 +80,47 @@ class PWAManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Показываем кнопку только на мобильных устройствах
|
||||||
|
if (!this.isMobileDevice()) {
|
||||||
|
console.log('Кнопка установки скрыта для ПК версии');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем, поддерживает ли браузер установку PWA
|
||||||
|
if (!this.deferredPrompt && !this.isMobileSafari()) {
|
||||||
|
console.log('Установка PWA не поддерживается в этом браузере');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const installButton = this.createInstallButton();
|
const installButton = this.createInstallButton();
|
||||||
this.addInstallButtonToPage(installButton);
|
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() {
|
createInstallButton() {
|
||||||
const installButton = document.createElement('button');
|
const installButton = document.createElement('button');
|
||||||
|
|
||||||
|
// Разный текст для разных браузеров
|
||||||
|
if (this.isMobileSafari()) {
|
||||||
|
installButton.textContent = '📱 Добавить на главный экран';
|
||||||
|
} else {
|
||||||
installButton.textContent = '📱 Установить приложение';
|
installButton.textContent = '📱 Установить приложение';
|
||||||
|
}
|
||||||
|
|
||||||
installButton.className = 'btnSave';
|
installButton.className = 'btnSave';
|
||||||
installButton.style.marginTop = '10px';
|
installButton.style.marginTop = '10px';
|
||||||
installButton.style.width = '100%';
|
installButton.style.width = '100%';
|
||||||
@ -132,6 +165,13 @@ class PWAManager {
|
|||||||
// Установка приложения
|
// Установка приложения
|
||||||
installApp() {
|
installApp() {
|
||||||
console.log('Попытка установки приложения');
|
console.log('Попытка установки приложения');
|
||||||
|
|
||||||
|
if (this.isMobileSafari()) {
|
||||||
|
// Для iOS Safari показываем инструкции
|
||||||
|
this.showSafariInstructions();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.deferredPrompt) {
|
if (this.deferredPrompt) {
|
||||||
this.deferredPrompt.prompt();
|
this.deferredPrompt.prompt();
|
||||||
this.deferredPrompt.userChoice.then((choiceResult) => {
|
this.deferredPrompt.userChoice.then((choiceResult) => {
|
||||||
@ -144,9 +184,32 @@ class PWAManager {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log('deferredPrompt не доступен');
|
console.log('deferredPrompt не доступен');
|
||||||
|
this.showManualInstallInstructions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Показать инструкции для Safari
|
||||||
|
showSafariInstructions() {
|
||||||
|
const instructions = `
|
||||||
|
Для установки приложения на iOS:
|
||||||
|
1. Нажмите кнопку "Поделиться" (□↗) внизу экрана
|
||||||
|
2. Выберите "На экран Домой"
|
||||||
|
3. Нажмите "Добавить"
|
||||||
|
`;
|
||||||
|
alert(instructions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Показать инструкции для ручной установки
|
||||||
|
showManualInstallInstructions() {
|
||||||
|
const instructions = `
|
||||||
|
Для установки приложения:
|
||||||
|
1. Откройте меню браузера (⋮ или ☰)
|
||||||
|
2. Найдите "Установить приложение" или "Добавить на главный экран"
|
||||||
|
3. Следуйте инструкциям браузера
|
||||||
|
`;
|
||||||
|
alert(instructions);
|
||||||
|
}
|
||||||
|
|
||||||
// Удаление кнопки установки
|
// Удаление кнопки установки
|
||||||
removeInstallButton() {
|
removeInstallButton() {
|
||||||
const installButton = document.getElementById('pwa-install-button');
|
const installButton = document.getElementById('pwa-install-button');
|
||||||
@ -167,7 +230,9 @@ class PWAManager {
|
|||||||
// Проверка статуса PWA
|
// Проверка статуса PWA
|
||||||
isPWAInstalled() {
|
isPWAInstalled() {
|
||||||
return window.matchMedia('(display-mode: standalone)').matches ||
|
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
|
// Получение информации о PWA
|
||||||
@ -177,7 +242,12 @@ class PWAManager {
|
|||||||
isOnline: navigator.onLine,
|
isOnline: navigator.onLine,
|
||||||
hasServiceWorker: 'serviceWorker' in navigator,
|
hasServiceWorker: 'serviceWorker' in navigator,
|
||||||
userAgent: navigator.userAgent,
|
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'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,14 +10,27 @@
|
|||||||
<meta name="theme-color" content="#007bff" />
|
<meta name="theme-color" content="#007bff" />
|
||||||
<meta name="mobile-web-app-capable" content="yes" />
|
<meta name="mobile-web-app-capable" content="yes" />
|
||||||
<meta name="apple-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="default" />
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||||
<meta name="apple-mobile-web-app-title" content="NoteJS" />
|
<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-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 -->
|
<!-- Icons -->
|
||||||
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
<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="32x32" href="/icons/icon-32x32.png" />
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/icons/icon-16x16.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="apple-touch-icon" sizes="180x180" href="/icons/icon-192x192.png" />
|
||||||
<link rel="mask-icon" href="/icon.svg" color="#007bff" />
|
<link rel="mask-icon" href="/icon.svg" color="#007bff" />
|
||||||
|
|
||||||
|
|||||||
33
public/sw.js
33
public/sw.js
@ -1,5 +1,5 @@
|
|||||||
// Service Worker для NoteJS
|
// Service Worker для NoteJS
|
||||||
const APP_VERSION = '1.0.2';
|
const APP_VERSION = '1.0.3';
|
||||||
const CACHE_NAME = `notejs-v${APP_VERSION}`;
|
const CACHE_NAME = `notejs-v${APP_VERSION}`;
|
||||||
const STATIC_CACHE_NAME = `notejs-static-v${APP_VERSION}`;
|
const STATIC_CACHE_NAME = `notejs-static-v${APP_VERSION}`;
|
||||||
|
|
||||||
@ -9,8 +9,16 @@ const STATIC_FILES = [
|
|||||||
'/index.html',
|
'/index.html',
|
||||||
'/style.css',
|
'/style.css',
|
||||||
'/manifest.json',
|
'/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-192x192.png',
|
||||||
'/icons/icon-512x512.png'
|
'/icons/icon-384x384.png',
|
||||||
|
'/icons/icon-512x512.png',
|
||||||
|
'/icon.svg',
|
||||||
|
'/logo.svg'
|
||||||
];
|
];
|
||||||
|
|
||||||
// Установка Service Worker
|
// Установка Service Worker
|
||||||
@ -71,6 +79,11 @@ self.addEventListener('fetch', (event) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Пропускаем запросы к внешним ресурсам
|
||||||
|
if (url.origin !== location.origin) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Обрабатываем только GET запросы
|
// Обрабатываем только GET запросы
|
||||||
if (request.method === 'GET') {
|
if (request.method === 'GET') {
|
||||||
event.respondWith(
|
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;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user