- Добавлены новые мета-теги и улучшены существующие для поддержки PWA. - Обновлен manifest.json с новыми полями для совместимости с Brave. - Улучшен Service Worker для кэширования манифеста и обработки ошибок. - Обновлены инструкции по тестированию PWA, включая новую тестовую страницу для Brave. - Оптимизирован код для обработки установки PWA на мобильных устройствах и в Brave.
334 lines
12 KiB
HTML
334 lines
12 KiB
HTML
<!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>
|