Перейти к основному содержимому

PWA в мобильных приложениях

Разработчику Архитектору Инженеру

PWA в мобильных приложениях

Прогрессивные веб-приложения (Progressive Web Apps, PWA) — это технологии, объединяющие возможности веб-сайтов и нативных мобильных приложений. Эти решения работают в браузере, но предоставляют функционал, сопоставимый с установочными программами: они могут работать офлайн, отправлять push-уведомления, добавляться на главный экран устройства и использовать аппаратные ресурсы смартфона.

PWA не требуют загрузки из магазинов приложений (App Store, Google Play). Пользователь получает доступ к приложению через URL-адрес. Браузер анализирует сайт и предлагает установить его, если он соответствует техническим требованиям. Установка происходит мгновенно и занимает минимум места на устройстве по сравнению с нативными аналогами.

Архитектура PWA строится на трёх ключевых компонентах. Первый компонент — Service Worker. Это скрипт, который работает в фоне между браузером и сетью. Он перехватывает все запросы к ресурсам сайта, управляет кэшированием и обеспечивает работу приложения без интернета. Второй компонент — Web App Manifest. Это JSON-файл, содержащий метаданные приложения: название, иконки, цвета темы, стартовый экран и ориентацию дисплея. Третий компонент — HTTPS. Все данные передаются только по защищённому протоколу, что гарантирует целостность информации и безопасность соединения.

Разработка PWA использует стандартные веб-технологии: HTML5, CSS3 и JavaScript. Разработчик пишет код один раз, и приложение работает на всех платформах, поддерживающих современные браузеры. Это включает Android, iOS, Windows, macOS и Linux. Единая кодовая база упрощает поддержку и обновление продукта. Изменения, внесённые в код, становятся доступны пользователям сразу после обновления сервера.

Особенности архитектуры

Архитектура прогрессивного веб-приложения отличается от классического сайта наличием слоя интерцепции. Service Worker выступает посредником между приложением и сетью. Когда пользователь открывает приложение, браузер загружает манифест и основной HTML-файл. Сразу после этого инициализируется Service Worker. Скрипт регистрируется и начинает управлять кэшем ресурсов.

При первом запуске Service Worker сохраняет основные файлы (HTML, CSS, JS, изображения) в локальное хранилище браузера. При последующих посещениях приложение загружается из кэша, даже если устройство находится в режиме полёта или сеть недоступна. Если новая версия файла доступна на сервере, Service Worker может обновить кэш в фоновом режиме, чтобы пользователь получил актуальный контент при следующем открытии.

Манифест определяет внешний вид приложения. Файл указывает, какие иконки использовать для разных размеров экрана, как называется приложение на главном экране и какой цвет отображать в статус-баре. Также манифест задаёт режим отображения. Значение standalone скрывает адресную строку браузера, создавая эффект нативного приложения. Значение minimal-ui оставляет минимальный интерфейс браузера. Значение fullscreen запускает приложение во весь экран без каких-либо элементов управления.

Безопасность является обязательным условием работы PWA. Сервер должен поддерживать HTTPS. Без шифрования трафика Service Worker не сможет зарегистрироваться. Это требование защищает пользователей от атак типа "человек посередине" и гарантирует, что код, выполняемый на устройстве, не был изменён третьими лицами.

Управление состоянием в PWA реализуется через комбинацию LocalStorage, IndexedDB и State Management библиотек. IndexedDB позволяет хранить большие объёмы структурированных данных, таких как списки товаров, история действий пользователя или офлайн-черновики документов. LocalStorage подходит для хранения простых настроек и флагов состояния.

Взаимодействие с аппаратными средствами смартфона осуществляется через Web APIs. Геолокация, камера, микрофон, вибрация и NFC доступны через стандартные интерфейсы браузера. Доступ к этим функциям требует явного разрешения пользователя. Браузер показывает системное окно с запросом прав доступа перед выполнением операции.

Push-уведомления в PWA работают через сервисный канал. Сервер отправляет сообщение на сервер уведомлений браузера (например, Firebase Cloud Messaging для Android или Apple Push Notification service для iOS). Service Worker перехватывает это сообщение и отображает уведомление на устройстве пользователя, даже если приложение закрыто. Это позволяет поддерживать вовлечённость аудитории без необходимости держать процесс запущенным.

Интеграция с операционной системой включает возможность добавления ярлыка на главный экран. При нажатии кнопки "Добавить на главный экран" браузер считывает данные из манифеста и создаёт иконку. При запуске приложения открывается в выделенном окне без рамок браузера. На Android это выглядит как отдельное приложение в списке установленных программ. На iOS PWA также можно добавить на домашний экран, хотя функционал ограничен некоторыми особенностями системы.

Адаптивность интерфейса обеспечивается использованием медиа-запросов и гибких верстальных решений. Приложение автоматически подстраивается под размер экрана, ориентацию устройства и плотность пикселей. Разработка учитывает различные форматы: смартфоны, планшеты, складные устройства и десктопы.

Создание первого приложения

Для создания базового PWA потребуется текстовый редактор, современный браузер и сервер для развертывания. Процесс начинается с подготовки структуры проекта. Создайте новую папку для вашего приложения. Внутри этой папки разместите три основных файла: index.html, manifest.json и service-worker.js.

Первым шагом является создание HTML-страницы. Этот файл служит входной точкой приложения. В секции <head> необходимо подключить манифест и добавить мета-теги для корректного отображения на мобильных устройствах. Укажите viewport для масштабирования и theme-color для цвета панели браузера.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Мое первое PWA</title>
<link rel="manifest" href="manifest.json">
<meta name="theme-color" content="#4a90e2">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<link rel="icon" type="image/png" sizes="192x192" href="/icons/icon-192.png">
<link rel="apple-touch-icon" href="/icons/icon-192.png">
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
color: #333;
}
.container {
max-width: 600px;
margin: 0 auto;
text-align: center;
padding: 20px;
background: white;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
h1 {
color: #4a90e2;
}
button {
background-color: #4a90e2;
color: white;
border: none;
padding: 12px 24px;
border-radius: 8px;
font-size: 16px;
cursor: pointer;
margin-top: 15px;
}
button:hover {
background-color: #357abd;
}
.status {
margin-top: 20px;
padding: 10px;
border-radius: 6px;
display: none;
}
.online {
background-color: #d4edda;
color: #155724;
}
.offline {
background-color: #f8d7da;
color: #721c24;
}
</style>
</head>
<body>
<div class="container">
<h1>Прогрессивное веб-приложение</h1>
<p>Это пример простейшего PWA.</p>
<button id="checkStatus">Проверить соединение</button>
<div id="statusMessage" class="status"></div>
</div>

<script>
// Регистрация Service Worker
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('Service Worker зарегистрирован:', registration.scope);
})
.catch(error => {
console.log('Ошибка регистрации Service Worker:', error);
});
});
}

// Логика проверки статуса сети
const statusDiv = document.getElementById('statusMessage');
const checkBtn = document.getElementById('checkStatus');

function updateStatus() {
if (navigator.onLine) {
statusDiv.textContent = 'Вы подключены к интернету';
statusDiv.className = 'status online';
statusDiv.style.display = 'block';
} else {
statusDiv.textContent = 'Вы в автономном режиме! Приложение работает.';
statusDiv.className = 'status offline';
statusDiv.style.display = 'block';
}
}

window.addEventListener('online', updateStatus);
window.addEventListener('offline', updateStatus);

checkBtn.addEventListener('click', updateStatus);
</script>
</body>
</html>

Вторым шагом является создание файла манифеста manifest.json. Этот файл сообщает браузеру о том, что сайт является приложением. Укажите имя приложения, короткий вариант имени, список иконок и настройки отображения. Иконки должны быть представлены в нескольких размерах: 192x192 и 512x512 пикселей. Для полноценной работы создайте эти изображения и сохраните их в папке icons.

{
"name": "Мое Первое PWA",
"short_name": "PWA Demo",
"description": "Простой пример прогрессивного веб-приложения",
"start_url": "/index.html",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#4a90e2",
"orientation": "portrait-primary",
"icons": [
{
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]
}

Третьим шагом является написание кода Service Worker в файле service-worker.js. Этот скрипт отвечает за кэширование и офлайн-режим. Он перехватывает события установки, активации и запросов. При установке сохраняем основные ресурсы в кэш. При получении запроса сначала проверяем кэш, и только если ресурс там отсутствует, запрашиваем его из сети.

const CACHE_NAME = 'pwa-cache-v1';
const urlsToCache = [
'/',
'/index.html',
'/styles.css',
'/app.js'
];

// Установка Service Worker
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
console.log('Кэширую ресурсы...');
return cache.addAll(urlsToCache);
})
);
});

// Активация Service Worker
self.addEventListener('activate', event => {
const cacheWhitelist = [CACHE_NAME];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});

// Перехват запросов
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
if (response) {
return response;
}
return fetch(event.request)
.then(response => {
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
const responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(cache => {
cache.put(event.request, responseToCache);
});
return response;
});
})
);
});

Четвертым шагом является подготовка иконок. Создайте два изображения размером 192x192 и 512x512 пикселей. Сохраните их в формате PNG в папку icons внутри корня проекта. Имя файлов должно соответствовать указанным в манифесте: icon-192.png и icon-512.png. Иконка должна иметь прозрачный фон или быть адаптированной под стиль приложения.

Пятый шаг — запуск сервера. PWA требуют использования HTTPS или localhost для тестирования. Используйте встроенные средства вашего редактора кода или команду npx http-server в терминале. Если вы используете Node.js, установите пакет и запустите сервер в корневой директории проекта.

npm install -g http-server
http-server -p 8080

Шестой шаг — проверка работоспособности. Откройте сайт в браузере Chrome или Edge. Перейдите в инструменты разработчика (F12) и выберите вкладку "Application". В разделе "Manifest" проверьте, отображаются ли данные правильно. В разделе "Service Workers" убедитесь, что статус показывает "Activated". Нажмите кнопку "Update on reload" для принудительной перезагрузки.

Седьмой шаг — тестирование офлайн-режима. Отключите интернет в инструментах разработчика (вкладка Network -> Offline). Обновите страницу. Приложение должно загрузиться из кэша без ошибок. Нажмите кнопку проверки статуса. Сообщение должно подтвердить отсутствие подключения.

Восьмой шаг — установка на устройство. На Android нажмите меню браузера и выберите "Добавить на главный экран". На iOS используйте кнопку "Поделиться" и выберите "На экран «Домой»". После добавления иконка появится среди других приложений. Запустите её. Приложение откроется в полноэкранном режиме без адресной строки.

Девятый шаг — оптимизация производительности. Используйте ленивую загрузку изображений и скриптов. Минифицируйте CSS и JavaScript файлы. Сжатие ресурсов уменьшает время загрузки и экономит трафик. Проверьте показатели Core Web Vitals через Lighthouse в инструментах разработчика.

Десятый шаг — распространение. Разместите проект на GitHub Pages, Netlify или Vercel. Эти платформы автоматически обеспечивают HTTPS. Поделитесь ссылкой с пользователями. Они смогут открыть сайт и установить приложение без участия магазинов приложений.


См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).