Как стать автором
Обновить
551.09
Сбер
Технологии, меняющие мир

Когда проснулся и узнал, что существуют PWA

Уровень сложностиПростой
Время на прочтение8 мин
Количество просмотров13K

Всем привет. Меня зовут Антон Непша, я фронтендер в Сбере, веду в Telegram канал nepshajs и недавно выступил на HolyJS с докладом про PWA. Если вы ещё не осваивали технологию PWA, но хотели бы — или вдруг срочно понадобилось, — то я вам помогу и объясню, что это и как начать с ней работать. 

Что за PWA?

Эта аббревиатура расшифровывается как Progressive Web App. Давайте объясню, что это такое по сравнению с WebView. Как вы, должно быть, знаете, WebView — это нативное приложение, которое способно внутри себя отображать веб-страницы. А PWA не имеет практически никакого отношения к нативным приложениям. Это всё тот же сайт, но который обманом пытается нас убедить в том, что он — приложение.

Зачем? Чтобы дать немного другой пользовательский опыт по сравнению с традиционным браузером. PWA позволяет убрать с экрана адресную строку и другие элементы браузерного интерфейса — панели инструментов, вкладок и прочего. При этом есть offline-режим, который обеспечивается с помощью кеширования и фоновых процессов. 

Ещё одна общая с мобильными приложениями черта — возможность не публиковать PWA в магазинах приложений. Это позволяет не отстёгивать комиссию владельцам магазинов, увеличивать конверсию, вовлечённость, длительность просмотра страниц и другие важные для бизнеса метрики. 

Возможно, кто-то подумал, что теперь начальство уволит всех мобильных разработчиков, оставит только фронтендеров и наделает из сайтов PWA, чтобы сэкономить кучу денег. Давайте разберёмся, так ли всё радужно и что нужно для создания PWA.

Так ли всё просто с PWA?

В 90 % руководств говорится, что для изготовления PWA нужен сайт, манифест и сервис-воркер. С сайтом, вроде бы, понятно, он у нас уже есть. Но оказывается, подойдёт не любой сайт. Напомню, что в PWA нет браузерного интерфейса. А если он вдруг сломается, мы же на JavaScript пишем? Что тогда делать пользователю? Он даже не сможет обновить экран, останется только принудительно закрыть процесс. Получается, дизайнеру нужно предусмотреть на сайте элементы управления для подобных случаев, и бэклог в Jira пополняется задачами.

Другой пример. Допустим, компания продаёт на своём сайте какие-то товары. Пользователь хочет отправить другу ссылку на понравившийся товар. А как это сделать? Адресной строки-то нет. 

Если в Android и Windows ещё как-то можно схитрить через системные меню, то в iOS так не получится. Поэтому вы снова бежите к дизайнеру и просите добавить некрасивую кнопку «поделиться» рядом с кнопкой «в корзину».

Это еще не всё. В статье на web.dev упоминается, что работать с несколькими origin будет сложно. Мои коллеги тоже с этим столкнулись, когда разрабатывали PWA-режим для веб-версии СберБанк Онлайн. Лучше использовать один домен. Так что если это ваш случай, скорее всего, придётся искать альтернативное решение. Например, переехать на общий домен и разбивать ваш сайт на подразделы с помощью внутренней маршрутизации.

Что такое манифест?

Это JSON-подобный файл, в котором указывается информация о вашем сайте, нужная для установки PWA и его работы. Путь до этого файла указывается в вашем index.html: 

// index.html
<link rel="manifest" href="manifest.webmanifest" />

В специфицации рекомендуется разрешение .webmanifest, но JSON тоже подойдёт. Его я и использую. В этом JSON мы указываем данные о приложении, которые будут использоваться при установке. 

У манифеста довольно простая структура, всего несколько полей, которые надо заполнить. Предлагаю пройтись по каждому из них. В поле name вводим название сайта. Идём дальше и видим поле shortName. Зачем оно? 

// manifest.json
{
"name": "Мой супер сайт",
"short_name": "Мй спр сйт"
}

Путаницы добавляет и то, что в спецификации разрешается использовать любое из них. Дело в том, что shortName будет использоваться в том случае, если содержимое name не помещается на экране, как обычно и бывает. Однако у меня на iPhone отображается shortName, даже тогда, когда name помещается целиком. Кроме того, ограничения по длине символов нет, можно туда вставить хоть «Войну и мир». Конечно, я не пробовал, но даже интересно, что будет. В общем, рекомендую вставлять в оба поля одинаковые значения, чтобы всё работало предсказуемо.

Следующее поле — display. C ним всё предельно просто: оно по умолчанию принимает значение browser, и мы видим обычный браузерный интерфейс. А магия с исчезанием адресной строки происходит, если мы используем display standalone или fullscreen. Любопытно, что можно завязаться на значение этого поля через media query и применить какие-нибудь стили в CSS, которые будут работать только в PWA-режиме.

// manifest.json
{
”display": "standalone”
}
// style.css
@media (display-mode: standalone) {
body {
background-color: #6667ab;
     }
}

Теперь как будто бы всё готово, PWA устанавливается и работает без браузерного интерфейса. Если нам этого достаточно, то действительно почти готово. Можно ещё в icons добавить набор иконок, которые отобразятся при установке и которые будут служить иконками вашего PWA на рабочем столе. А в поле screenshots можно добавить скриншоты вашего приложения, которые будут отображаться при установке вашего PWA в Windows.

// manifest.json
{”
icons": [{
          ”src": ”/icon.webp”,
          ”sizes": ”48x48”,
          ”type": ”image/webp”,
        }],
        ”screenshots": [{
          ”src": ”/screenshot1.webp”,
          ”sizes": ”1280x720”,
          ”type": ”image/webp”,
        }]
}

Другие поля манифеста

Теперь рассмотрим поля start_url, scope и id. В start_url вписывайте тот URL вашего сайта, на который должен попадать клиент, когда он открывает приложение. Со scope посложнее, придётся подумать над формулировками: этот URL — граница работы вашего PWA. Если клиент выйдет за пределы этого URL, то вы снова увидите элементы браузерного интерфейса. Это будет выглядеть примерно так же, как в обычных мобильных приложениях, когда вы переходите по ссылке и у вас открывается встроенный браузер.

id ещё интереснее. Если вы захотите поменять start_url, — например, под какую-то акцию, — то благодаря тому, что id останется прежним, браузер поймёт, что это то же самое приложение и не потребует заново его переустанавливать. 

Но обратите внимание, что есть нюансы. 

Во-первых, start_url не может быть вне scope, иначе вы поделите на ноль. Кстати, это легко обойти, если вместо абсолютного пути указать относительный. Главное, не поставить точку, например, ./login, потому что тогда это будет путь относительно файла manifest.json на сервере. 

Во-вторых, в start_url не рекомендуется хранить данные о пользователе: его ID или ник, чтобы не собирать информацию втайне от людей (об этом есть сноска в спецификакции в разделе «Privacy and security». 

В-третьих, сменить start_url не так просто. Я два дня пытался, и выяснил, что нужно дважды перезапустить браузер, и между запусками настраивать браузер в разделе about://web-app-internals, если вы работаете с Chrome. Подробности здесь. Причём это работает только в Windows. В Android и iOS ситуация интереснее. Так я вывел для себя путь джедая в работе с манифестом для PWA. 

Путь джедая

Читаешь спецификацию — находишь интересное поле или функциональность — реализуешь — тестируешь, а дальше — развилка, 50 на 50: либо работает, либо нет. Во втором случае начинаешь искать информацию в сети. И далеко не всегда удаётся найти объяснение.

Можно изучить популярные PWA. Один из первых — AliExpress. Заходим на их сайт, в application находим манифест, а там пустые поля name и short name. 

/* aliexpress */
{
  "name": "",
  "short_name":"",
  "icons": […],
  "theme_color":"#ffffff",
  "background_color":"#ffffff",
  "display":"standalone"
}

Посмотрим PWA Pinterest. Там какие-то странные поля, которые даже в спецификации не указаны. Например, url_handlers с разными доменами. Вроде бы, стоит взять на вооружение, но копнув информацию, выясняется, что это поле означает не то, что вы могли подумать, и вообще оно уже было переименовано и сейчас не применяется (1, 2). Почему авторы PWA Pinterest его оставили, я не знаю. Ещё есть gcm_sender_id, но это поле использовалось в устаревшей реализации PUSH-уведомлений

Так вот, путь джедая таков, что чужие примеры могут не помочь и придётся костылить, чтобы просто работало. Благо, со start_url проблем нет, можно в JavaScript в любой момент поменять адрес и маршрутизировать пользователя. 

Хоть что-нибудь работает?

Моё любимое поле — theme_color. Оно отвечает за цвет панели статуса сверху, принимает значения HEX, HSL и CMYK. Этот же цвет будет заполнять экран позади окна сайта. При этом окно может масштабироваться, и если его цвет отличается от theme_color, то выглядит некрасиво. Я сэкономлю вам время на поиск решения: 

  • Делайте одинаковые theme_color и background_color, тогда масштабирования никто не заметит.

  • Либо запретите масштабирование через тег <meta name=”viewport” content=”width=device-width, initial-scale=1, maximum-scale=1”>. Останется только прокрутка вверх-вниз. 

  • Либо можно сделать в CSS:

body {
	position: fixed;
}

А что делать, если у вас в theme_color должен быть градиент? Увы, не получится. Остаётся только обходной путь: сделать «цветомузыку» с предупреждением Seizure Alert, или с завязкой на настройку prefers-reduced-motion, чтобы соблюдать доступность.

// index.html
<meta name=”theme-color" content=”#ffbe98" />
// whatever.js
document.head.querySelector(‘meta[name=“theme-color”]’)
  ?.setAttribute(‘content’, ‘red’)

// index.html
<meta name=”theme-color" content=”#ffbe98" media=”(prefers-color-scheme: light)" />
<meta name=”theme-color" content=”#333456" media=”(prefers-color-scheme: dark)" />

Это же решение можно использовать для выделения премиум-пользователей, для подержки светлой и тёмной тем. Есть метатеги, отвечающие за иконки установки и приложения, за отображение имени, и другие. Не все из них приоритетнее манифеста, theme_color из тех, чей приоритет выше. Дело в том, что когда PWA ещё только создавали, всё работало на метатегах, манифеста ещё не было. В конце концов сообщество устало поддерживать обилие метатегов во множестве index.html. Так и пришли к идее единого источника истины — к манифесту (1, 2). Поэтому, если вы ориентируетесь на современные версии ОС, то рекомендую пользоваться манифестом. А если вас интересуют относительно старые версии, вроде iOS 11, то можете использовать метатеги.

Краткие промежуточные выводы про манифест

Можете взять за основу набор полей из PWA AliExpress: коротко, понятно и по делу. Но только не забудьте заполнить name и short_name.

/* aliexpress */
{
  "name": "",
  "short_name":"",
  "icons": […],
  "theme_color":"#ffffff",
  "background_color":"#ffffff",
  "display":"standalone"
}

Если вам этого недостаточно, то можно ориентироваться на интересующую платформу. Например, в Windows в манифесте есть поля, позволяющие учитывать открытие ещё одного экземпляра приложения. Выбор полей зависит также и от ваших бизнес-целей, от задач PWA. И напомню, что у манифеста приоритет выше, чем у большинства метатегов.

Service worker

Ещё один инструмент, который может понадобится вашему PWA — это Service Worker. 

Он отвечает за offline-режим, фоновые задачи, кеширование и использование WebAPI. Допустим, вы хотите добавить в своё приложение возможность отправки пользователям PUSH-уведомлений. Для этого, с помощью Service Worker и Push API мы запрашиваем у пользователя согласие на получение уведомлений. Как только пользователь соглашается, появляется специальный объект PushSubscription, который мы сохраняем на сервере. И когда нужно будет отправить какое-то сообщение на устройство, мы вызываем специальную конечную точку, которая хранится в этом объекте как значение одного из свойств. Далее вызываем push-сервис (он сторонний, то есть мы не можем на него повлиять), а он вызвает устройство пользователя. И даже если мы закроем PWA, устройство всё-равно поднимет браузер и наш зарегистрированный service worker, и получит уведомление (1, 2). 

Почему веб-приложение становится progressive?

Я считаю, что всё это благодаря WebAPI, которые мы используем в своём приложении, а не благодаря service worker или манифесту. С них и нужно начинать. Посмотрите, какие из них поддерживаются, сравните с тем, что требуется вашему бизнесу и приложению. И тогда станет понятно, получится ли реализовать нужные функции. Для этого есть хороший инструмент whatpwacando.today, это PWA со ссылками на всевозможные WebAPI, каждый из которых можно протестировать на любом устройстве. Например, у «Сбербанка Онлайн» есть PWA-режим, и там есть аутентификация по биометрии: можно подключить FaceID и TouchID, или любую другую аутентификацию, она прекрасно будет работать с WebAuthn. Также можно на иконки ставить бейджики, отмечая наличие непрочитанных сообщений. Есть и push-уведомления. А возможность подгружать контакты зависит от вашей платформы и версии браузера.

Выводы

Отличие PWA on WebView в том, что WebView — это нативное Android-приложение, которое мы пишем на Kotlin или Java, и встраиваем кусочек сайта, а PWA — это просто сайт, который мы сохраняем на рабочий стол или на экран «Домой». PWA не заменяет нативные приложения. Это дополнение, вишенка на торте вашего сайта, новая функциональность. Прирост конверсии, о которой я говорил в начале статьи, рассчитывался не в сравнении с нативным приложением, а в сравнении с сайтом без PWA

Начинайте создавать PWA с выбора Web API. И обязательно думайте об удобстве использования. Главное, чтобы люди были довольны.

Теги:
Хабы:
Всего голосов 30: ↑27 и ↓3+32
Комментарии14

Информация

Сайт
www.sber.ru
Дата регистрации
Дата основания
Численность
свыше 10 000 человек
Местоположение
Россия