В 2022 году многим российским компаниям пришлось адаптировать мобильные приложения и решать проблемы, вызванные международными санкциями.
Когда мобильное приложение ВТБ было удалено из Google Play, сразу встал вопрос — как пользователи смогут получать обновления? В нашем случае это вопрос доступа миллионов клиентов, которые уже установили Android-приложение «ВТБ Онлайн», к банковским услугам. При поиске решения заодно удалось сократить размер приложения в 2 раза — до 220 Мб.
Где публиковать заблокированное в GooglePlay приложение
Самый очевидный ответ — на сайте банка ВТБ Онлайн. Потом появились отечественные аналоги Google Play: Наш Store, Ru Store и RuMarket. Кроме того, опубликовали приложение, Get Apps (Xiaomi), Galaxy Store (Samsung). Эти площадки не поддерживают разделения на архитектуры.
Как происходила публикация приложения в Google Play.
Нужен аккаунт разработчика
Нужно само приложение
Нужно текстовое описание и картинки
Нужно сделать сборку и отправить её на ревью
После ревью новый релиз приложения появлялся в магазине
Сложностей с публикацией в другие магазины не было: везде процесс был похожим. При этом не везде нужна отправка на ревью — несколько файлов под разную архитектуру публикуется непосредственно на сайте банка.
Для пользователей тоже сложностей с обновлениями не возникло, т. к. для всех сборок передавались одни и те же файлы, подписанные одной подписью. В итоге если первая установка приложения была с Google Play, то её можно спокойно обновить с любого другого магазина.
Так мы решили основной вопрос — с обновлением и установкой приложения.
Осталось решить второй вопрос — с его размером.
Почему тяжёлому приложению нужно худеть
Можно выделить четыре проблемы больших приложений:
Долгая загрузка обновления или приложения. Пользователи не готовы ждать и часто прерывают процесс, отменяя загрузку.
Мобильные операторы отказываются от безлимитных подписок, а с пакетом интернета, скажем, в 5Гб — регулярно обновлять приложение дорого.
У многих пользователей на телефонах мало свободной памяти, и большое приложение может банально не поместиться на телефоне.
В некоторых сторах есть ограничение на скачивание слишком больших приложений и предлагается скачивать такие файлы только по Wi-Fi.
Так что в любом случае сокращать размер приложения нужно.
Как мы затягивали пояса и избавлялись от лишнего
Сборки и архитектуры
Для ВТБ Онлайн мы использовали сборку-бандл, которая состояла из установочных пакетов под разные архитектуры. Она грамотно упакована с учётом общих данных для разных архитектур, и бандл весил немного по сравнению с тем же APK. Когда пользователь начинал скачивать приложение с Google Play, было понятно, какая у него архитектура, и скачивалось уже оптимизированное под его устройство. Именно поэтому на Google Play не было проблем с размерами приложений. Например, если бандл весил 200 Мб (под разные архитектуры), пользователь скачивал с Google Play приложение весом 80 Мб, уже оптимизированное под конкретное устройство.
Кроме создания бандла, можно собрать универсальный APK, который будет работать на любой архитектуре, но это приводит к увеличению веса приложения. В случае с ВТБ Онлайн универсальный APK до оптимизаций весил около 400 Мб. Сразу забегу вперёд: нам удалось сократить размер универсального APK до 220 Мб. Сейчас поддерживаются 4 архитектуры:
armeabi-v7a — более бюджетные и старые модели ARM;
arm64-v8a — более новые и дорогие модели ARM;
x86 — более старые 32-битные модели x86;
x86_64 — более новые 64-битные модели x86.
Библиотеки и ресурсы
Вес сторонних SDK обычно не является существенным, но в совокупности они составляют большую часть веса финального APK. Поэтому 13 нативных (.so) библиотек мы удалили сразу, сократив размер финального APK на 252,063 Мб:
Долго думали, что делать с оставшимися библиотеками. Может, переписать их своими силами? В итоге пока убрали в них некоторые неиспользуемые функции, а также отказались от нескольких фич.
Часть кода написана на Java, часть — на Kotlin (Kotlin — целевой язык для новых проектов). Была кодогенерация в Dagger и Synthetic, а также байтового кода. Поэтому поставили задачи по оптимизации этих процессов, что также сократило размер APK. Кстати, при оптимизации Dagger были сложности при выделении и разделении графа даггера (их тоже удалось решить).
Флаги minifyEnabled (запускающий анализатор ProGuard и удаляющий неиспользуемый код) и shrinkResources (удаляющий ресурсы, которые ProGuard пометил как «неиспользуемые») в приложении были изначально включены — так что тут уже не оптимизируешь. Зато удалось оптимизировать Lint на уровне CI, что упростило код-ревью и избавило от проблемы увеличения веса приложения.
Много места занимали и ресурсы. Провели в команде анализ, что с ними можно сделать. Оказалось, что у многих .png- и .webp-ресурсы не были включены в оптимизацию и частенько попадались картинки с метаданными. У больших картинок сократили размер. Какие-то картинки уменьшились автоматически, над некоторыми пришлось поработать вручную, подбирая степень оптимизации. Некоторые картинки сжались очень сильно. Рекорд — картинка стала в 100 раз меньше. В итоге сократили 30 Мб по всем плотностям ресурсов за счёт их оптимизации. Если говорить о сборках под конкретный DPI — там выигрыш поменьше.
При анализе ресурсов было найдено множество старых ресурсов, которые были оставлены как техдолг и благополучно забыты. Но эти ресурсы могли неявно использоваться, и поиск мест для них делался проблематичным. Так что решили пока «стариков» не трогать.
В итоге получилось следующее соотношение библиотек, ресурсов и кода:
Риски оптимизации приложения
При оптимизации под разные архитектуры стоит проверить корректность работы на телефонах от разных производителей. Потому что то, что не используется у одного производителя, может оказаться обязательным для другого. И тогда оптимизация может привести к критичным проблемам на некоторых устройствах. Поэтому желательно после подобных оптимизаций тестировать на большом количестве устройств.
При оптимизации библиотек есть вероятность удалить и сами библиотеки, и их функции, которые используются не напрямую, а подключаются динамически (например, через lazy в Kotlin). А это станет заметно только на этапе Runtime. Так что по каждой функции библиотеки, которая планируется к удалению, стоит запустить глобальный поиск и убедиться, что её удаление не нарушит работу приложения.
При удалении ресурсов — если воспользоваться возможностями Android Studio — можно удалить динамически подключаемые ресурсы. Многие ресурсы, подключаемые в классе, статический анализатор может посчитать неиспользуемым. Поэтому надо по каждому «подозрительному» проводить отдельное исследование.
При использовании флагов minifyEnabled=true и shrinkResources=true есть вероятность, что анализатор ошибочно посчитает динамически подключаемый код и ресурсы неиспользуемыми. А это приведёт к ошибкам и даже падению приложения. Поэтому нужно внимательно настраивать правила в ProGuard.
В целом, если приложение имеет высокий процент покрытия unit-тестами, большинства рисков при оптимизации можно избежать.
Вместо заключения
Собственно, мы вернули пользователям возможность скачивать обновления и устанавливать приложение «ВТБ Онлайн». Попутно уменьшили размер приложения вдвое и решили множество технических задач.
Дальше по оптимизации планируем:
переписать сторонние библиотеки своими силами — это упростит их обновление, сократит размер и тоже повысит безопасность;
наше приложение не использует технологию BFF (backend for frontend), и в планах не было делать dynamic module.
Итого рассчитываем, что скоро приложение «ВТБ Онлайн» станет ещё легче.
А как вы оптимизировали размер своих приложений? Пишите в комментариях.