[Из песочницы] Подводные камни разработки Google Play Instant

r4z7fgs6v1btcn8gyo2t23xro_c.jpeg

Привет, Хабр! Меня зовут Камо Сперцян, я занимаюсь Android-разработкой в PROFI.RU. Недавно я написал приложение с мгновенным запуском для наших клиентов. Если вы ещё не знакомы с технологией, приглашаю вас сначала посетить Android Developers.

С презентации Instant Apps (Google Play Instant) на Google I/O 2016 прошло больше двух лет. В сети множество статей о том, как создавать приложения с мгновенным запуском. Судя по ним, ничего сложного в этом нет. Но на деле это не совсем так. Я постараюсь описать основные трудности, через которые мне пришлось пройти от создания пустого проекта до публикации Instant App в Google Play. Надеюсь, статья окажется полезной разработчикам, которым этот путь ещё предстоит.

Выбор подхода


В большинстве источников описывается процесс конвертирования основного приложения целиком в Instant App. Однако наше приложение никак не соответствовало ограничению в 4 МБ и предоставляло гораздо большую функциональность, чем требовалось для ознакомления с сервисом перед установкой. Сейчас Google в тестовом режиме увеличил допустимый размер приложения с мгновенным запуском до 10 МБ.

У меня был выбор из двух подходов к созданию Instant App. Первый — взять готовое приложение и вырезать из него ненужную функциональность. Второй — создать пустой проект и перенести в него функциональность, которая необходима. Посчитав первый вариант быстрым, мы с коллегами опробовали его на локальном хакатоне и тогда же убедились в его безнадёжности. Во-первых, на это ушло много времени (порядка 40 человеко-часов). Во-вторых, размер приложения оказался очень большим из-за лишнего кода и ресурсов. В-третьих, лишний код усложнял сопровождение. Мы судорожно пытались уместить получившееся приложение в 4 МБ за время хакатона, и в итоге всё равно не успели.

Перенос функциональности


Наученный горьким опытом, я создал пустой проект и стал копировать в него только нужные модули приложения. У нас поддерживается модульная архитектура, поэтому сделать это было несложно. Здесь я столкнулся с первой проблемой — в Instant Apps нельзя использовать сервисы. В моём случае это ограничение не оказалось критичным: мы использовали сервис для загрузки фотографий, а в Instant App от этой фичи отказались, мотивируя пользователей скачать основное приложение. Но этот момент стоит учитывать, если ваше приложение тоже использует сервисы.

К моему удивлению, полученное копированием только нужных кусков кода приложение всё равно не влезло в допустимые 4 МБ и весило около 5 МБ. В этой статье Google даёт советы на этот случай, но мне они мало помогли. Единственное, от чего мы могли отказаться, — кастомные шрифты, но их вес существенно не влиял на размер APK.

Тут я вспомнил, что ProGuard у нас в проекте отключён на debug-сборках. Простое включение

minifyEnabled true


сократило размер приложения чуть ли не вдвое. О чудо — ограничение в 4 МБ соблюдено!

Миграция данных


Далее предстояло решить вопрос с миграцией данных. Как известно, Instant Apps поддерживаются операционной системой Android с версии 5.0. При этом автоматическая миграция данных работает только начиная с Android 8.0. Для этого достаточно использовать в обоих приложениях файлы shared preferences с одинаковым названием. Для версий с 5.0 по 7.1 миграцию нужно писать вручную с помощью Cookie API или Storage API. Я воспользовался Cookie и с особыми проблемами не столкнулся — правда, это потребовало изменений не только на стороне Instant App, но и в устанавливаемом приложении. Так что в итоге пришлось выпустить новую версию приложения и раскатить её на всю аудиторию для релиза Instant App.

Отладка


С отладкой всё оказалось не так просто.

Во-первых, Google Play Instant не поддерживает незащищённые сетевые соединения, так что забудьте про http, только https. Для меня это означало тестирование на production-серверах, так как все тестовые стенды работали по http. Не критично, но приятного мало.

Во-вторых, сам запуск Instant App: вы можете тестировать приложение как обычное, устанавливаемое, но лишь до поры до времени. При запусках через Android Studio невозможно проверить обновление Instant App до «полноценного» приложения. Например, протестировать, насколько корректно перенесутся данные пользователя. Для этого нужно запускать приложение с мгновенным запуском именно как Instant App. Сделать это можно двумя способами:

  1. запустить приложение с помощью специальной утилиты из Android SDK;
  2. выложить его в консоль для внутреннего тестирования и запустить через Play Market.


Первый способ достаточно удобен. Утилита входит в Android SDK, но по умолчанию не установлена. Для установки в Android Studio нужно выполнить следующие шаги:

  1. зайти в PreferencesAppearance & BehaviorSystem SettingsAndroid SDK;
  2. выбрать вкладку SDK Tools;
  3. поставить галочку возле Google Play Instant Development SDK и нажать Apply.


v4jsdwq8brx2kcids6tgeann2-8.gif
На последнем шаге обратите внимание на директорию, в которую будет установлена утилита. Далее относительно этого пути нас будет интересовать файл ./extras/google/instantapps/ia. С его помощью можно сымитировать мгновенный запуск приложения, выполнив команду

ia run <путь к APK-файлу, bundle-у или URL>


До момента, как я наткнулся на эту утилиту, я использовал второй способ, с постоянной публикацией приложения в Google Play Console. Но так как опубликованное приложение появляется в магазине не сразу, а по истечении неопределённого времени (у меня это занимало от получаса до суток), такой способ тестирования никуда не годился. Впрочем, он для этого и не предназначен. Кстати, если вы публикуете Instant App в Google Play Console с большой частотой, советую предусмотреть возможность после запуска определить код версии приложения. Иначе бывает сложно понять, запустилась последняя опубликованная версия или предыдущая.

Публикация


Наконец, когда ваше приложение протестировано и готово к публикации, не спешите расслабляться! Во-первых, код версии (versionCode) Instant App не должен превышать код версии устанавливаемого приложения. Рекомендую заранее дать простор для творчества: указать при релизе основного приложения заведомо большое значение кода, чтобы не связывать себе руки. Удалить выпущенный Instant App из консоли с целью «высвободить» код версии для другой сборки не получится. Формально у вас имеется N-M возможностей зарелизить Instant App, пока у вас в Google Play основное приложение с versionCode = N и приложение с мгновенным запуском с versionCode = M.

Также для релиза Instant App убедитесь, что оно будет доступно не большей аудитории, чем основное приложение. Иными словами, каждый пользователь Instant App должен иметь возможность установить основное приложение.

На аудиторию в первую очередь влияют разрешения приложения, указываемые в Manifest-файле (permissions), — они должны быть одинаковыми для обоих приложений (за исключением разрешений, не влияющих на аудиторию). Скажем, если ваше основное приложение требует разрешение на определение геопозиции, а в Instant App это не нужно, всё равно нужно его указать и там, и там.

Также некоторые вспомогательные библиотеки могут сузить круг конечных пользователей. Так было и в нашем случае. Консоль выдавала ошибку «targeting apk difference», хотя разрешения обоих приложений были одинаковыми. В поисках решения я наткнулся на этот вопрос со Stack Overflow, где советуют прогнать APK файлы приложений через утилиту aapt. Она выведет подробную информацию о файлах, включая все зависимости. Вычислив разницу в выдаче по обоим файлам, я заметил зацепку: у устанавливаемого приложения была строка uses-gl-es: '0x20000', которая отсутствовала в Instant App. Недолгий сёрфинг по сети привёл меня к разгадке: эта строка говорит, что приложение использует библиотеку OpenGL, которая, в свою очередь, используется в картах. И действительно, наше основное приложение использовало библиотеку play-services-maps, а Instant App — нет. Добавление этой зависимости в Instant App позволило мне в конце концов зарелизить приложение.

Подытожим


  1. В Instant Apps нельзя использовать сервисы и незащищённые сети (http). Размер конечного APK-файла не должен превышать 4 МБ (возможно, скоро это ограничение упростят до 10 МБ).
  2. Для уменьшения размера APK-файла можно применять оптимизаторы и обфускаторы кода (например, ProGuard).
  3. Перенос SharedPreferences из Instant App в основное приложение происходит автоматически для Android 8.0+, для более ранних версий необходимо писать вручную через Cookie API или Storage API. Стоит учесть необходимость релиза подготовленного к миграции данных устанавливаемого приложения перед релизом Instant App.
  4. Для отладки Instant App можно воспользоваться специальной утилитой из Google Play Instant Development SDK, входящего в Android SDK.
  5. Появление опубликованного в консоли Instant App на конечных устройствах может происходить с задержкой от получаса до суток. Стоит позаботиться о возможности однозначно определить, какая версия Instant App сейчас запустилась из Play Market.
  6. Код версии Instant App не должен превышать код версии основного приложения.
  7. Список устройств, которым будет доступен Instant App, не должен превышать список устройств, которым доступно основное приложение. Для этого следует указывать в Manifest-файлах одинаковые разрешения, а также обратить внимание на возможные ограничения из-за вспомогательных библиотек.


На этом всё. Надеюсь, эта информация окажется для вас полезной. Буду рад любой обратной связи!

Полезные источники:


  1. Документация по Google Play Instant на Android Developers
  2. Советы по уменьшению размера APK-файла Instant App
  3. FAQ по Google Play Instant
  4. Миграция данных с помощью Cookie API
  5. Миграция данных с помощью Storage API

© Habrahabr.ru