Разработка Artem Menchenya
6605

Загружаем сайт в Google Play

В идеальном мире вы создаёте продукт и не думаете, как его портировать под все существующие платформы (web, Android, iOS, Windows). Мы ещё не в идеальном мире, но с развитием технологии Progressive Web Application (PWA) мы движемся туда уверенно и стремительно.

В закладки

У вас есть интернет-магазин, веб-приложение или личный блог? Давайте сделаем так, чтобы он появился в магазине приложений Google.

Концепция

PWA — это технология, которая позволяет сайту получить функциональность мобильного приложения. Можно, в частности, реализовать работу приложения в офлайне, отправлять push-уведомления пользователям, взаимодействовать с внутренними службами и сервисами смартфона (геолокация, камера, панель уведомлений).

При установке из браузера на Android-смартфон или на компьютер с Windows PWA получает свой значок, ничем не отличающийся от других приложений.

В iOS нет возможности напрямую установить приложение, это можно сделать только добавив сайт на главный экран. Но мы уверены, что ребята из Купертино обязательно всё наверстают в самое ближайшее время. PWA можно добавить в Windows Store и Google Play (с небольшими усилиями).

В англоязычном интернете есть статьи о том, как добавить PWA-приложение в App Store, но мы это ещё не практиковали.

Шаг первый — создание PWA

Для реализации PWA нам потребуются сайт, Manifest и Service Worker.

Сайт

Свой пример мы будем строить на проекте «Чердак Дали», веб-ресурсе для художников. Единственное требование к сайту — SSL-сертификат (реализация https). Если у вас нет такой функции, рекомендуем обратиться к вашему хостинг-провайдеру, скорее всего, сертификат можно добавить бесплатно с помощью сервиса Let's Encrypt.

Нам нужен только доступ к файлам проекта, никакие серверные изменения или сложные механики не требуются.

Manifest

Нужно дать браузеру подробную информацию о нашем ресурсе: как он называется, как отображать его на конечном устройстве, какие иконки использовать. Это всё мы описываем в файле manifest.json. Мы не будем делать это вручную, а используем онлайн-генератор.

Предварительно нужно создать иконку для своего приложения размером 512 на 512 пикселей. Изображения остальных размеров сервис создаст самостоятельно. Заполняем все поля (название, короткое название, цветовая тема), выбираем режим отображения standalone, добавляем иконку и генерируем архив.

На выходе мы получим архив, в котором будут находиться сам файл manifest.json, а также иконки нашего приложения. Переносим эти файлы в корневую папку вашего сайта.

Service Worker

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

Для большинства задач хватит сгенерированного кода. Для этого воспользуемся PWA Builder.

  1. Вводим адрес своего сайта.
  2. Нажимаем на ссылку Choose a service worker.
  3. В новом окне выбираем подходящий вариант (в нашем случае мы выбрали Advanced Caching) и нажимаем на кнопку Download.

В итоге мы получим архив с двумя файлами. Файл pwabuilder-sw.js переносим в корневую папку сайта (к файлу manifest.json).

Нам нужно разместить файл pwabuilder-sw-register.js в корне сайта и просто добавить в конец нашего сайта (перед закрывающимся тегом body) новый тег script со ссылкой:

<script src=”/pwabuilder-sw-register.js”></script>

Альтернативный способ

Во втором файле хранится JavaScript-код для запуска service-worker. Этот код необходимо перенести в JS-файл вашего сайта. Чтобы определить, куда и в какой файл записать код, откройте сайт в браузере и зайдите в режим просмотра кода страницы (в Google Chrome это комбинация клавиш Ctrl+U).

Файлы JavaScript подключаются к сайту с помощью тега script. Ищем такой тег в начале (в секции head) или в конце сайта (перед закрывающимся тегом body).

Если тегов несколько (как правило присутствуют JS-файлы подключаемых библиотек), ищем самый последний из них. В теле тега содержится информация о том, где находится нужный нам файл (в нашем случае это файл app.js в папке js). В конец этого файла мы вставляем код из файла pwabuilder-sw-register.js.

На данном этапе у нас есть работающее PWA-приложение. При заходе на сайт с Android-смартфона внизу должна появится ссылка на установку приложения на главный экран.

Шаг второй — создание мобильного приложения

Для создания приложения нам потребуется бесплатная среда разработки Android Studio.

Начнём создание нашего проекта. На начальном экране Android Studio нажимаем Start a new Android Studio project. На следующем шаге нам предлагают выбрать заготовку для нашего приложения. Выбираем вариант Add No Activity и двигаемся дальше.

В следующем окне нужно заполнить информацию о новом приложении: имя, название пакета (уникальное имя приложения в Google Play), локация проекта на компьютере, язык программирования, а также минимальная версия операционной системы. Для нашего проекта мы заполнили информацию так:

Система создаст для нас новый проект. Для дальнейших действий нам нужно подключить к проекту библиотеку TWA Support Library. Для этого нужно открыть файл build.gradle:

Вначале внесём изменения в файл, у которого в описании стоит название вашего проекта (в нашем случае это файл build.gradle (Project: Cherdak)). Нам нужно добавить дополнительный репозиторий в секцию repositories:

maven { url 'https://jitpack.io' }
Пример дополнения кода

Теперь нам нужен файл, у которого в описании написано Module:app. Это файл, в котором мы можем добавить зависимости в наш проект. В секцию dependencies добавляем следующую запись:

implementation 'com.github.GoogleChrome:custom-tabs-client:a0f7418972'
Пример дополнения кода

Необходимая нам библиотека требует восьмой версии Java, поэтому нам нужно добавить её в опции компиляции. Для этого добавим следующий код в блок android:

compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 }
Пример дополнения кода

Нам также нужно специфицировать переменную manifestPlaceholders. Добавляем следующий код в секцию defaultConfig, меняя значения переменных на собственные:

manifestPlaceholders = [ hostName: "cherdak.org", defaultUrl: "https://cherdak.org", launcherName: "Cherdak" ]

На этом с файлом build.gradle мы закончили. Теперь нам нужно переместиться в файл AndroidManifest.xml. В этом файле хранится информация о нашем приложении.

Нам нужно добавить код для отображения нашего приложения:

<activity android:name="android.support.customtabs.trusted.LauncherActivity" android:label="${launcherName}"> <meta-data android:name="android.support.customtabs.trusted.DEFAULT_URL" android:value="${defaultUrl}" /> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter android:autoVerify="true"> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE"/> <data android:scheme="https" android:host="${hostName}"/> </intent-filter> </activity>

Обратите внимание, что мы раскрыли тег application.

Пример дополнения кода (раскрытый тег выделен синей рамкой)

Теперь нам нужно подтвердить взаимоотношение приложения и сайта. Связь должна быть установлена с обеих сторон — со стороны сайта и со стороны приложения. Для этого мы должны добавить изменения в файл build.gradle (Module: app). Не забываем менять значения на собственные:

assetStatements: '[{ "relation": ["delegate_permission/common.handle_all_urls"], ' + '"target": {"namespace": "web", "site": "https://cherdak.org"}}]'
Пример дополнения кода

Возвращаемся в файл AndroidManifest.xml и добавляем новые метаданные:

<meta-data android:name="asset_statements" android:value="${assetStatements}" />
Пример дополнения кода

Мы закончили устанавливать связь со стороны приложения. Теперь нам нужно установить связь со стороны сайта. Для этого сгенерируем файл assetlinks.json и разместим его на сервере. Для начала нам нужно сгенерировать APK-файл. Переходим во вкладку Build → Generate Signed Bundle or APK и выбираем APK.

Нам нужно сформировать новый keystore (или воспользоваться существующим, если он у вас есть). Нажимаем на кнопку Create new… и заполняем поля:

На следующей вкладке выбираем release и ставим галочки в Signature Versions:

После клика на клавишу Finish мы получим APK файл, который в дальнейшем сможем передать в Google Play.

Теперь перемещаемся во вкладку Tools → App Links Assistant.

Это откроет окно, в котором описаны шаги, необходимые для связывания сайта и приложения. В этом окне кликаем на кнопку Open Digital Asset Links File Generator и в открытом окне вводим URL сайта, ставим галочку на Select keystore file и выбираем ключ, который мы сформировали на предыдущем шаге:

Сохраняем полученный файл и переносим его в папку .well-known на сервер.

Пример дополнения кода

И нажимаем клавишу Link and Verify. В появившемся окне нажимаем OK. В итоге мы должны увидеть следующее:

Шаг третий — регистрируемся в Google Play, формируем материалы и выкладываем приложение

Для того, чтобы иметь возможность публиковать приложения в магазин Google Play, необходимо получить аккаунт разработчика. Для этого регистрируемся (стоимость аккаунта — $25 разовым платежом.

После регистрации у вас появится доступ к Google Play Console. Нажимаем на клавишу «Новое приложение». В следующем окне заполняем все необходимые данные (описание, возрастные ограничения, графические материалы).

Система сама подскажет, какие данные обязательны к заполнению. Мы не будем останавливаться на данном шаге: с нашей точки зрения, если вы дошли до этого шага, то вы определённо справитесь. Отметим только, что файл apk, который нужно загрузить, находится в папке «Папка с проектом/app/release/app-release.apk».

После загрузки пройдёт некоторое время, пока Google Play будет проверять ваше приложение. В конечном счёте вы сможете увидеть заветный статус «Опубликовано», после чего — ищите на просторах Google Play.

Спасибо, что прошли этот путь вместе со мной. Надеюсь, у вас всё получилось! Если нет, я постараюсь ответить на ваши вопросы. Обязательно поделитесь своими сайтами-приложениями в комментариях к этой статье.

Материал для вас готовила команда агентства Ilavista. Мы занимаемся разработкой сайтов и веб-приложений для бизнеса.

#googleplay #приложения

Материал опубликован пользователем. Нажмите кнопку «Написать», чтобы поделиться мнением или рассказать о своём проекте.

Написать
{ "author_name": "Artem Menchenya", "author_type": "self", "tags": ["\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f","googleplay"], "comments": 27, "likes": 35, "favorites": 101, "is_advertisement": false, "subsite_label": "dev", "id": 76260, "is_wide": false, "is_ugc": true, "date": "Mon, 22 Jul 2019 13:24:07 +0300" }
{"average":28186,"one":95,"ten":76}
Сколько денег вы откладываете в месяц?
Ответьте и узнаете, сколько копят другие.
0 ₽
70 000+ ₽
0 ₽
{ "id": 76260, "author_id": 114615, "diff_limit": 1000, "urls": {"diff":"\/comments\/76260\/get","add":"\/comments\/76260\/add","edit":"\/comments\/edit","remove":"\/admin\/comments\/remove","pin":"\/admin\/comments\/pin","get4edit":"\/comments\/get4edit","complain":"\/comments\/complain","load_more":"\/comments\/loading\/76260"}, "attach_limit": 2, "max_comment_text_length": 5000, "subsite_id": 235819, "last_count_and_date": null }
27 комментариев

Популярные

По порядку

Написать комментарий...
4

Отношусь к этой идее с большим скепсисом. Когда человек качает приложение, он ожидает увидеть именно самостоятельное приложение, а не копию сайта. Это подразумевает знакомые паттерны поведения, которые существуют чтобы пользователю было проще ориентироваться в новых приложениях. Для этого используются схожие элементы дизайна, анимации, и т.д. И если вы не делали сайт в соответствии с гайдами Material (если мы говорим об Android), пользователь немного офигеет от вашего "приложения".

Ответить
1

Если сайт делается не адаптивным - конечно пользователь офигеет. С другой стороны, большинство современных адаптивных сайтов использует те же элементы, что и мобильные приложения - бургер-меню, float-button, side navigation и т.д. используются так же, как и нативных приложениях.

Ответить
1

Да не, если нормально делать, то они выглядят как приложения.

Правда гугл подводит и при первом открытии сообщает пользователю, что для работы приложения используется Google Chrome. Мои пользователи из-за этого обижаются)) А так бы совсем чисто всё выглядело.

Ответить
3

Я давно пытался сделать что-то подобное на андроид для своего проекта "Taskker" https://taskker.club пока не узнал о существовании PWA и просто перевел сайт на эту технологию. В итоге отложил идею андроид-приложения в "долгий ящик" ибо "зачем платить больше, если не видишь разницы?".
Однако, по-моему среднестатистический пользователь будет ещё долго привыкать к PWA (и не факт, что привыкнет), он хочет видеть приложение в знакомом ему Play Market, поэтому данная статья очень даже актуальна. Спасибо!

P.S. По-моему в приложении неплохо было бы совсем убрать адресную строку (напишите как это сделать), чтобы у пользователя было ощущение, что это полноценное приложение, а не просто страница в браузере.

Ответить
1

Мы продолжаем экспериментировать, обязательно напишем, если придумаем как убрать адресную строку. Спасибо за обратную связь!

Ответить
1

нужна просто оболочка которая отобразит сайт внутри приложения без адресной строки?

Ответить
1

Да, но проблема в том, что в нашем случае используется Trusted Web Activities, а она в свою очередь имеет адресную строку по-умолчанию. Мои знания в Android-разработке не очень высокие, я думаю что это нельзя обойти. Надеюсь, что ошибаюсь :)

Ответить
1

Как-то начинал писать статью как обернуть сайт в приложение на iOS и Android, но забросил. Завтра тогда подниму материалы и размещу статью.

Я делал с 4-мя нижними табиками, чтобы хоть что-то было от мобильного приложения, иначе Apple не пропускает.

Ответить
1

Будет интересно почитать

Ответить
1

Так адресная строка же убирается сама. Важно, чтобы все URL приложения были продолжением start_url, и всё.

Ответить
3

Есть еще такой сервис https://appmaker.xyz/pwa-to-apk/. Там не нужно возиться с Android Studio.
Стоит отметить что у пользователя должен быть свежий Google Chrome (пока только он поддерживает). Иначе приложение будет выглядеть как вкладка браузера. Технология называется вроде как TWA

Ответить
1

Интересный сервис, еще не пробовали. Обязательно напишем рецензию. Технология называется Trusted Web Activity (TWA) - гугл тому, кому интересно глубже погрузиться в тему.

Ответить
2

Кордову не пробовали?

Ответить
1

Нет, сбросьте ссылку

Ответить
0

Кордова другую задачу решает - упаковать приложние-подобный код js+html в apk, как обычный сайт оно не будет нормально работать. Тут же смысл в том, что у вас и сайт и приложение работают с одним кодом и сайт ещё висит в сети.

Ответить
0

что мешает подключать мобильный js-код, если он есть, и cordova.js только на этапе сборки мобильного приложения?

Ответить
0

хотелось бы увидеть более подробные комментарии к каждому из этапов. зачем и почему нужны те или иные вставки кода? хочется понимать

Ответить
0

В таком случае получится очень длинный материал. Мы старались сделать максимально коротко, только практика. В дальнейшем будем разбирать отдельно каждый этап (создание индивидуальных service worker, настройка проекта в Android studio и т.д ), поэтому следите за обновлениями

Ответить
1

Потому что размер сборки webpack-a 2 МБ. То есть прежде, чем сайт откроется, пользователь должен подождать, пока в его браузер подгрузится 2МБ JavaScript-кода.

Чтобы исправить:
1. Нужно минимизировать сборку webpack (см. UglifyPlugin). Но вообще новые версии webpack по умолчанию минимизируют.
2. Сжать дополнительно сборку gzip-ом.

Предполагаю, что в результате сборка составит килобайт 100 вместо 2МБ, а перфоманс подлетит 70+

Ответить
0

Не в бровь, а в глаз 😉 Надеюсь, автор обратит внимание.

Ответить
0

Да, все верно. И полностью согласен, что косяк :) просто деплоим иногда по несколько раз в день - иногда забываем залить продакшн-файлы, а не девелопмент-файлы. Мы сейчас на стадии наращивания функционала, который уже давно закладывали, но все время откладывали. После будет этап оптимизации. В любом случае, спасибо за совет!

Ответить
0

Нет, пока добавляем кучу функционала - после будем оптимизировать.

Ответить
0
{ "page_type": "article" }

Прямой эфир

[ { "id": 1, "label": "100%×150_Branding_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox_method": "createAdaptive", "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfl" } } }, { "id": 2, "label": "1200х400", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfn" } } }, { "id": 3, "label": "240х200 _ТГБ_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fizc" } } }, { "id": 4, "label": "240х200_mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "flbq" } } }, { "id": 5, "label": "300x500_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfk" } } }, { "id": 6, "label": "1180х250_Interpool_баннер над комментариями_Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "bugf", "p2": "ffyh" } } }, { "id": 7, "label": "Article Footer 100%_desktop_mobile", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjxb" } } }, { "id": 8, "label": "Fullscreen Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjoh" } } }, { "id": 9, "label": "Fullscreen Mobile", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjog" } } }, { "id": 10, "disable": true, "label": "Native Partner Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyb" } } }, { "id": 11, "disable": true, "label": "Native Partner Mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyc" } } }, { "id": 12, "label": "Кнопка в шапке", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "p1": "bscsh", "p2": "fdhx" } } }, { "id": 13, "label": "DM InPage Video PartnerCode", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox_method": "createAdaptive", "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "bugf", "p2": "flvn" } } }, { "id": 14, "label": "Yandex context video banner", "provider": "yandex", "yandex": { "block_id": "VI-223676-0", "render_to": "inpage_VI-223676-0-1104503429", "adfox_url": "//ads.adfox.ru/228129/getCode?pp=h&ps=bugf&p2=fpjw&puid1=&puid2=&puid3=&puid4=&puid8=&puid9=&puid10=&puid21=&puid22=&puid31=&puid32=&puid33=&fmt=1&dl={REFERER}&pr=" } }, { "id": 15, "label": "Плашка на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byudx", "p2": "ftjf" } } }, { "id": 16, "label": "Кнопка в шапке мобайл", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byzqf", "p2": "ftwx" } } }, { "id": 17, "label": "Stratum Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fzvb" } } }, { "id": 18, "label": "Stratum Mobile", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fzvc" } } }, { "id": 19, "label": "Тизер на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "p1": "cbltd", "p2": "gazs" } } } ]
Голосовой помощник выкупил
компанию-создателя
Подписаться на push-уведомления
{ "page_type": "default" }