По умолчанию R8 выполняет множество оптимизаций, чтобы повысить производительность и уменьшить размер приложения, но эти оптимизации могут не сразу подойти для вашего приложения. Если вы впервые включаете R8 (или полный режим) в большом приложении, попробуйте внедрять оптимизацию постепенно: временно отключите обфускацию и включите R8 для отдельных частей кода, а не для всего кода приложения. Мы рекомендуем использовать этот подход во время локальной разработки, но вы также можете использовать его во время внутреннего контроля качества или даже в рабочей версии в качестве постепенного развертывания. Конкретные шаги зависят от желаемой хронологии и уверенности в покрытии тестирования предварительного выпуска.
Ограничить оптимизацию
R8 выполняет множество типов оптимизации, включая удаление кода, перезапись кода и удаление ресурсов. Ниже приведены краткие описания типов оптимизации.
- Сокращение кода (или tree shaking) – удаление неиспользуемого кода.
- Обфускация (или минимизация идентификаторов): сокращает названия классов и методов.
- Оптимизация: переписывает код, например встраивает функции.
Чтобы снизить вероятность ошибок, сначала включите только некоторые из этих оптимизаций.
Включить только удаление неиспользуемого кода
Сокращение кода, также известное как tree shaking, удаляет код, на который нет ссылок. Рекомендуем начать с Tree Shaking, так как это самый простой способ.
Чтобы включить только удаление неиспользуемого кода, добавьте в файл proguard-rules.pro следующий код, который отключит другие типы оптимизации: Это важно, поскольку так трассировки стека будет проще читать.
-dontobfuscate // Use temporarily to turn off identifier minification
-dontoptimize // Use temporarily to turn off optimization
В конечном итоге вы не захотите поставлять эту конфигурацию, поскольку она резко ограничивает возможности R8 по оптимизации кода, но это отличная отправная точка при первом внедрении R8 в большую базу кода с проблемами, которые необходимо исправить.
Как использовать режим совместимости
По умолчанию R8 работает в полном режиме. Полный режим обеспечивает значительное повышение производительности и экономию места, но вы можете временно отключить его и использовать режим совместимости при первом включении минификации.
Чтобы использовать режим совместимости, добавьте в файл gradle.properties следующую настройку:
android.enableR8.fullMode = false // Use temporarily to disable full mode
Включите остальные варианты оптимизации
Когда вы убедитесь, что удаление неиспользуемого кода работает в вашем приложении, вы можете удалить приведенные выше настройки, чтобы снова включить обфускацию, оптимизацию и полный режим R8. Обратите внимание, что обфускация может затруднить отладку, поэтому мы рекомендуем сначала устранить проблемы с удалением неиспользуемого кода.
Подробнее о том, как восстановить исходную трассировку стека…
Ограничьте область оптимизации
Полностью оптимизированная сборка оптимизирует весь код во всех библиотеках и пакетах, поэтому при первом включении R8 часто возникают проблемы. Если вы обнаружите проблему с оптимизацией в одной части приложения, не отключайте R8 полностью, иначе вы потеряете преимущества в других частях. Вместо этого временно отключите R8 только в тех частях приложения, которые вызывают проблемы.
Как использовать правила сохранения на уровне пакета
Мы рекомендуем использовать правила сохранения на уровне пакета, чтобы временно отключить R8 в некоторых частях приложения. Позже вам нужно будет вернуться к этим проблемам оптимизации и устранить их. Это временное решение, позволяющее обойти проблемные области.
Например, если в какой-то части приложения активно используется Gson и это приводит к проблемам с оптимизацией, лучше всего добавить больше целевых правил сохранения или перейти на решение с генерацией кода. Чтобы разблокировать оптимизацию остальной части приложения, вы можете поместить код, определяющий типы Gson, в отдельный подпакет и добавить в файл proguard-rules.pro следующее правило:
-keep class com.myapp.json.** { *; }
Если в используемой вами библиотеке есть отражение во внутренние компоненты, вы можете добавить правило сохранения для всей библиотеки. Чтобы найти нужный пакет, вам потребуется проверить код библиотеки или JAR/AAR. Мы не рекомендуем использовать этот подход в долгосрочной перспективе, но он может помочь разблокировать оптимизацию остальной части приложения:
-keep class com.somelibrary.** { *; }
Как удалить правила хранения на уровне пакета
После того как вы убедитесь, что приложение работает правильно с правилами сохранения на уровне пакета, вернитесь к этому этапу и добавьте целевые правила сохранения или удалите использование отражения или библиотеку, для которой изначально требовалось правило сохранения.
Например, в AndroidX часто сохраняются все правила, расширяющие определенный класс, чтобы оставить только нужные классы. Как правило, рефлексия должна быть нацелена только на классы или методы, которые расширяют определенные абстрактные классы, реализуют определенные интерфейсы или входят в классы с определенной аннотацией времени выполнения. Каждый из этих способов позволяет задавать правила сохранения, чтобы в финальной, полностью оптимизированной версии приложения не было правил сохранения для всего пакета.
Если в вашей базе кода есть рефлексия, вы можете заменить правила сохранения на уровне пакета на Jetpack Keep. Сгенерированные правила являются условными: R8 сохраняет цель рефлексивного вызова, только если он также сохраняет код, который выполняет вызов. Чтобы перенести пакет, используйте проверки Jetpack Keep lint, чтобы найти и аннотировать его рефлексивные вызовы, а затем удалите правило для всего пакета.