
Привет, Хабр! Меня зовут Влад, и я тот самый человек, который привык использовать костыли в решении задач. По крайней мере, я считаю, что это лучший подход при подготовке MVP. Яркий пример — прототипирование простых скриптов под микроконтроллеры на MicroPy или десктопных приложений на Electron. Но, как оказалось, это не все виды ухищрений в разработке.
Если вы веб-разработчик, но руки «чешутся» написать мобильное приложение, варианты есть. В этой статье я расскажу, как создать собственное прогрессивное веб-приложение (PWA) и доработать его до TWA, чтобы потом протестировать и опубликовать в разных сторах. Никакого rocket science, просто небольшое пособие, которое основывается на моем опыте. Подробности под катом.
Что такое PWA и TWA
Если вы ранее не сталкивались с такими понятиями, давайте сделаем краткий экскурс.
PWA (Progressive Web App) — это веб-приложение, которое старается быть похожим на нативное приложение. По сути — просто сохраненная страница браузера на главном экране вашего устройства. При этом интерфейс самого браузера может быть отключен, чтобы все выглядело максимально правдоподобно. При этом PWA может работать без подключения к интернету, если настроены сервис-воркеры (Service Workers), которые загружаются в память самого устройства и кэшируют ресурсы.
TWA (Trusted Web App) — это, можно сказать, улучшенный PWA. По сути, это уже не сохраненная страница, а полноценный «браузер» на движке Chrome, у которого одно предназначение — отображать ваше веб-приложение. Подробнее о том, чем TWA отличается от PWA, вы поймете по ходу статьи. Здесь есть свои тонкости.
Подготовка веб-страницы
По какой-то причине вы решили, что не хотите писать отдельный нативный фронтенд на Swift и Java/Kotlin. И это очень даже логично, если вы разрабатываете MVP продукта или просто хотите ограничиться небольшим количеством ресурсов. Далеко за примером ходить не нужно, ведь разный фронтенд — это отдельный бэкенд со своим проработанным API и спецификацией. А тут написали «монолит» на Django, конвертировали каким-то образом в подобие мобильного приложения — и готово.
Оставим шутки в сторону, я слишком утрирую. На самом деле, разделить фронтенд и бэкенд я настоятельно советую, чтобы в будущем было проще масштабировать проект. Но пока сконцентрируемся на фронтенде.
Допустим, у вас есть страница, а в инструментах разработчика все выглядит красиво. На этом этапе важно убедиться, что верстка будет не столько адаптивной, сколько резиновой — чтобы приложение адекватно выглядело, например, на IPhone 12 Pro и вытянутом Galaxy Z Fold 5. Здесь рекомендую использовать величины, относительные ширины или высоты устройства:
vh
, vw
и т. д. По опыту, работать с упором на ширину гораздо проще.
Инструменты разработчика, Google Chrome.
Резиновая верстка есть — с этим уже можно работать и делать PWA. Или нет?
Прежде необходимо также указать в мета-тегах цвет статус-бара — панели, на которой размещена информация об уровне заряда, сети и времени. Вы можете определять ее
background-color
относительно каждой HTML-страницы своего веб-приложения. Достаточно прописать такую строку внутри блока :<meta name="theme-color" content="#FFFFFF">
В остальном, рекомендую много времени на стилизацию и шлифование верстки не тратить — вы к этому вернетесь еще не один раз. Ведь у каждого устройства свои стандартные стили отображения веб-элементов и их состояний, которые точно отразятся на итоговом результате.
Запуск PWA
Сегодня прогрессивные веб-приложения — это не rocket science. По сути, чтобы превратить свой веб-сайт в веб-приложение, нужно добавить простой манифест. В нем — указать параметры запуска PWA: ориентацию, иконку, дисплей и так далее. После того, как мобильный браузер «считает» этот манифест, он предложит сохранить приложение на экран «Домой» вашего смартфона. Кстати, именно поэтому раньше Apple называли прогрессивные веб-приложения как «Home Screen Web Apps».

Кнопка сохранения PWA приложения на экран «Домой».
Звучит все просто, не так ли? Давайте тогда напишем и подключим манифест.
Шаг 1. Создайте manifest.json на стороне фронтенда вашего приложения.

Шаг 2. Сконфигурируйте manifest.json. Для простоты можете воспользоваться Manifest Generator — он в онлайне все сделает за вас.
{
"name": "Приложение",
"short_name": "Приложение",
"start_url": "/master.html",
"display": "standalone",
"background_color": "#FFFFFF",
"orientation": "portrait",
"icons": [
{
"src": "/static/img/global/pwa/logo_128x128.png",
"type": "image/png",
"sizes": "128x128"
},
{
"src": "/static/img/global/pwa/logo_144x144.png",
"type": "image/png",
"sizes": "144x144"
},
{
"src": "/static/img/global/pwa/logo_512x512.png",
"type": "image/png",
"sizes": "512x512"
}
]
}
Шаг 3. Откройте файл, указанный в
start_url
, и подключите manifest.json:<!DOCTYPE html>
<html lang="en">
<head>
<meta name="theme-color" content="#FFFFFF">
<meta charset="UTF-8">
<title>Приложение</title>
<link rel="manifest" href="manifest.json">
<link rel="stylesheet" type="text/css" href="static/styles/global/base.css">
<link rel="stylesheet" type="text/css" href="static/styles/global/panelist.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
</head>
Шаг 4. Создайте app.js и sw.js. В первом скрипте может быть собрана основная логика вашего приложения — он отвечает за взаимодействие с пользователем, обработку событий, управление состоянием приложения и взаимодействие с API.
Подключение app.js в теле основного файла master.html:
<body>
<script src="static/scripts/global/pwa/app.js" defer></script>
<script src="static/scripts/global/lottie-web/lottie.js"></script>
<script src="static/scripts/global/tunnel_config.js"></script>
…
</body>
В app.js вы можете инициализировать необходимые функции, такие как регистрация Service Worker, настройка кэширования, обработка офлайн-режима и другие функции, которые сделают ваше приложение интерактивным и отзывчивым.
В файле sw.js должна быть описана логика Service Worker — скрипта, который работает в фоновом режиме, отдельно от основного потока вашего приложения. Например, с помощью него можно регулярно отправлять сетевые запросы и управлять оффлайн-доступом. Чтобы было понятнее: если приложение неактивно, Service Worker может работать в фоне и периодически отправлять пользователю push-уведомления.
Отладочное наполнение app.js, а сам sw.js может быть пустым, если вы не хотите описывать специфический Service Worker:
if('serviceWorker' in navigator){
navigator.serviceWorker.register('/scripts/global/pwa/sw.js')
.then(() => console.log("pwa start"))
.catch(() => console.log("pwa error"));
}
Шаг 5. Запустите свой веб-сервер и откройте master.html. Если вы все сделали корректно, в консоле будет сообщение «pwa start». Важно: PWA лучше запускать, если у вас настроено HTTPS-соединение. Тогда приложение не будет ругаться и всячески ограничивать сбор данных вроде геолокации и прочего.
Готово! Вот так за пять шагов мы настроили PWA. По сути, вы можете на этом закрыть статью и пойти дальше разрабатывать свое веб-приложение. На ограничения здесь наткнуться сложно, ведь PWA имеет доступ к драйверам камеры и файловой системы, что довольно сильно приближает его к нативным приложениям.

Результат: веб-страница запущена в виде PWA на iOS.
Есть только один нюанс: PWA нельзя разместить в сторе. Если вам это нужно, то оставайтесь на связи и читайте следующий раздел.
Разработка TWA
Если вы слышали раньше, что PWA можно загрузить в Microsoft App Store и Google Play — это правда. Но есть несколько нюансов.
- Вы не сможете опубликовать PWA в AppStore. В этом плане Apple враждебны в отношении веб-приложений. Отчасти это связано с тем, что они не могут знать, что вы реализуете на базе JavaScript. А если у вас нативное приложение, вам проще выписать чек за работу с драйверами геолокации, камеры, вибрации и прочего.
- PWA зависит от ПО на устройстве пользователя. Да, сегодня технологию поддерживают большинство браузеров, но кто знает наверняка? Хотя, честно говоря, в этот нюанс верится уже с натяжкой.
В общем, чтобы ваше приложение можно было распространять через все сторы, нужно само «нативное приложение». А PWA — это просто вкладка браузера, сохраненная на экран смартфона. Это значит, нам нужно распространять не саму вкладку, а браузер с этой вкладкой. С этим поможет инструмент Cordova.
Cordova — это платформа от Apache для разработки кроссплатформенных мобильных приложений с использованием веб-технологий. По сути, она создает «браузер», в котором по умолчанию запущено только ваше веб-приложение через iframe или WebView.
Важно: Cordova — это не единственный путь для создания мобильных приложений на базе веб. Есть еще Ionic Framework Quasar Framework. Но я с ними не работал, поэтому не могу рекомендовать. А вот как работать с Cordova, знаю.
Шаг 1. Создайте внутри среды разработки отдельный проект и установите node.js в виртуальное окружение. Это можно сделать по инструкции с официального сайта.
Шаг 2. Установите Cordova. Для этого в терминале достаточно ввести команду:
npm install -g cordova
Шаг 3. Создайте новый проект. В качестве myApp укажите название проекта (не используйте кириллицу, будут проблемы с зависимостями):
cordova create myApp
Шаг 4. Перейдите в каталог проекта и добавьте необходимые платформы: Android или iOS.
cd myApp
cordova platform add ios
cordova platform add android
Шаг 5. Установите необходимые плагины. Полный список доступен на сайте. Для примера установим плагины для работы с камерой устройства и геолокацией:
cordova plugin add cordova-plugin-camera
cordova plugin add cordova-plugin-geolocation
Шаг 6. Опишите конфигурацию config.xml — здесь вы можете задать ориентацию, базовый цвет темы и статус-бара и другие параметры:
<?xml version='1.0' encoding='utf-8'?>
<widget id="com.example.myapp" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<name>MyApp</name>
<description>
A sample Apache Cordova application.
</description>
<author email="you@example.com" href="http://example.com">
Your Name
</author>
<content src="index.html" />
<access origin="*" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
<allow-navigation href="http://*/*" />
<allow-navigation href="https://*/*" />
<preference name="StatusBarBackgroundColor" value="#F3F3FA" />
<preference name="StatusBarOverlaysWebView" value="false" />
<preference name="orientation" value="portrait" />
<!-- Параметры платформ -->
<platform name="android">
<preference name="android-minSdkVersion" value="21" />
<preference name="android-targetSdkVersion" value="30" />
</platform>
<platform name="ios">
<preference name="deployment-target" value="11.0" />
</platform>
<!-- Плагины -->
<plugin name="cordova-plugin-camera" source="npm" />
<plugin name="cordova-plugin-geolocation" source="npm" />
</widget>
Обратите внимание: после установки плагинов их нужно инициализировать в config.xml, иначе они будут проигнорированы. Также в конфигурации указана мета-информация о создателе приложения и другие данные. А чтобы статус-бар браузера (навигация, поисковая строка) не отображались пользователю, мы его скрыли через настройку
StatusBarOverlaysWebView
. Также мы указали портретную (вертикальную) ориентацию.Шаг 7. Создайте WebView вашего приложения. Для этого откройте файл www/index.html и используйте шаблон:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
<meta name="theme-color" content="#FFFFFF">
<title>My Cordova App</title>
<link rel="stylesheet" href="css/index.css">
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript">
document.addEventListener('deviceready', function() {
var url = 'https://url.to.your.frontend';
var ref = cordova.InAppBrowser.open(url, '_blank', 'location=no,toolbar=no,hideurlbar=no');
StatusBar.backgroundColorByHexString("#FFFFFF");
ref.addEventListener('loadstop', function(event) {
console.log('Страница загружена: ' + event.url);
});
ref.addEventListener('exit', function() {
console.log('InAppBrowser закрыт');
StatusBar.show();
});
}, false);
</script>
</head>
<body>
<div class="app">
<h1>Добро пожаловать в мое Cordova приложение!</h1>
<p>Открывается страница в WebView...</p>
</div>
</body>
</html>
Шаг 8. Соберите приложение. Важно: для запуска эмулятора iOS вам понадобится XCode, а для Android — Android Studio.
cordova build ios
Шаг 9. Запустите приложение:
cordova run ios
Готово — мы получили готовое приложение, которое можно запустить на iOS:

Далее вы можете собрать приложение через XCode или Android Studio (зависит от платформы) и загрузить на реальное устройство или выложить в стор. Это тема для отдельной статьи, так что оставлю ее вам на самостоятельное изучение.
Тестирование PWA/TWA
В зависимости от устройства верстка может ломаться. И, на самом деле, это меньшая из проблем. Например, если вы используете асинхронный JavaScript, который рендерит что-то на клиенте, процесс может поломаться на более «быстром» или «медленном» устройстве. Чтобы найти все такие баги, приложение нужно тестировать и отлаживать.
Если вы работаете с устройствами Apple, можно подключить смартфон по кабелю к MacBook и в режиме разработчика в Safari отслеживать алерты, которые скрыты за интерфейсом PWA. Но это не универсальное решение, ведь вы ограничены своим устройством, его платформой и характеристиками.
Наверное, вы к этому моменту уже догадались, что для разработки TWA совершенно необязательно делать PWA. Это независимые подходы, которые просто похожи по своей задумке. Но я считаю, что пренебрегать PWA, если вы хотите сделать TWA, не стоит.
С точки зрения верстки пересобирать TWA под каждую из платформ — долго и нецелесообразно. Если вы хотите протестировать работу плагинов Cordova с драйверами разных устройств — да, без TWA никуда. Но чтобы проверить верстку, достаточно запускать на разных смартфонах одно PWA и смотреть, как оно себя ведет. И с первым, и вторым может помочь ферма мобильных устройств.
Ферма мобильных устройств — это инфраструктурное решение для удаленного тестирования под Android и iOS. Имея доступ к большой базе смартфонов с различными параметрами (версиями OS, процессорами, диагоналями, производительностью и оболочкой), пользователь может проводить широкий набор тестов. Тем самым — ускорить обнаружение багов и деплой в продакшен.
Шаг 1. Зарегистрируйтесь в панели управления Selectel и откройте раздел Продукты → Мобильная ферма.

Панель управления, экран создания фермы мобильных устройств.
Шаг 2. Нажмите кнопку Создать ферму — введите имя фермы и выберите устройства, на которых хотите протестировать свое приложение. Для примера возьмем Android-смартфон TECNO CAMON 20 Pro и iPhone 12 Pro Max. Такая ферма будет стоить всего 2 ₽/мин.

Панель управления, сборка фермы мобильных устройств.
Шаг 3. Нажмите кнопку Создать ферму и кликните по устройству, на котором хотите протестировать свое PWA/TWA.

Панель управления, интерфейс работы с устройством.
Шаг 4. Загрузите свое TWA перетаскиванием в поле Приложения вашего скомпилированного приложения. Или, если вы тестируете PWA, просто откройте в браузере нужную ссылку и нажмите Установить приложение.

Панель управления, работа со смартфоном.
Готово! Вот так с помощью небольших манипуляций можно протестировать свое приложение в бою.
Надеюсь, статья была полезной. Поделитесь в комментариях, что думаете о TWA и Cordova? Какие инструменты используете вы? Или предпочитаете использовать React и делать нативные приложения с помощью React Native? Интересно узнать ваше мнение.