Как стать автором
Обновить

R8: Шакалья работа (уменьшение apk через правки R8)

Уровень сложностиСложный
Время на прочтение3 мин
Количество просмотров1.3K
TL;DR

Если расширить алфавит который используется в r8 для минификации, то может уменьшиться размер обновлений apk и dex файлов.

Дисклеймер

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

По умолчанию для минификации имени класса используются цифры и английский алфавит*. Чтобы использовался верхний регистр нужно в .pro файлах убрать флаг dontusemixedcaseclassnames.

Для первых классов R8 будет использовать строки из одного символа. Когда они будут все использованы, R8 будет использовать строки из двух символов и так далее. Если включен флаг repackageclasses, который перемещает классы в один package, то при большом количестве классов, в итоговом apk часто можно будет увидеть минифицированные классы с тремя и более символами. Для кодировки символов в dex используется MUTF-8. Это UTF-8 с некоторыми изменениями, но в текущем контексте они не важны и можно считать что используется UTF-8.

Основной вопрос, что будет если например вместо трех символьных строк, которые будет занимать три байта, использовать один двухбайтовый символ? Публичного api для такого изменения нет, поэтому нужно будет собрать свою сборку R8 и подменить дефолтную реализацию R8.

Как внести правки и собрать R8?

  • Скачать исходники https://r8.googlesource.com/r8/ и найти класс com.android.tools.r8.utils.SymbolGenerationUtils. В нем функция numberToIdentifier на вход принимает “порядковый номер” объекта (класс, поле, package и т.д.), а выходе выдается минифицированная строка. На этом моменте будет достаточно просто добавить kotlin.jvm.functions.Function1<Integer, String> которая будет воспроизводить нашу логику по минификации имен. 

  • Желательно знать и собрать версию R8 той же версии которая будет использоваться в проекте. Для этого в android проекте можно прописать println(com.android.tools.r8.Version.getVersionString()) где будет показана версия R8 и хеш коммита на котором собиралось.

Как заменить R8 на проекте?

Для этого нужно добавить собранный jar как зависимость до добавления AGP. Что бы точно быть уверенным что найдено правильно место можно добавить из maven старую версию R8, например com.android.tools:r8:1.0.20. Если при сборке будет ошибка значит место найдено верное. В него уже можно прописать путь к jar с правками которая была собрана выше.

Как добавить логику для кастомной минификации.

Как вариант можно взять такой класс и добавить его в релизную сборку.

Тестовые результаты

Для проверки работоспособности мы возьмем приложение wikipedia для андроида (assembleAlphaRelease) с включенной минификацией и repackageclasses.

Root git hash

Apk**

Dex

Patch size***

Original

88f4767d

34 245 774

11 437 344

c94d1b73

34 709 027

12 382 396

3 689 417

Fix

88f4767d

34 207 236

11 435 996

c94d1b73

34 660 697

12 380 648

3 609 380

Вывод

Увеличение размера алфавита потенциально дает выигрыш в размере apk, dex и размере обновлений за счет уменьшения количества символов которые нужно использовать для минификации одного и того же количества классов. На сколько будет уменьшение зависит от количества кода которое находится в dex файлах.

Текущий пример с приложением wikipedia показывает небольшое уменьшение размера apk и размера обновлений, в рамках десяток килобайт. Отчасти это связано с тем что приложение не сильно большое, в рамках 100 тысяч методов. В замерах приложений с 500 тысяч методов и более уменьшение размера apk уже идет в рамках сотен килобайт, а размера обновлений в рамках мегабайта.


* В документации по dex формату, есть строка “The .dex format allows a fair amount of latitude here (much more than most common source languages)”. Скорее всего тут имеется в виду что по Java Language Specification имена классов не могут начинаться с цифр, что можно в dex формате.

** apkanalyzer apk file-size

*** apkanalyzer apk compare --patch-size

Теги:
Хабы:
Всего голосов 3: ↑3 и ↓0+4
Комментарии0

Публикации

Работа

Ближайшие события