Если вы включите оптимизацию приложения с настройками по умолчанию, R8 выполнит ряд действий, чтобы максимально повысить производительность. R8 вносит существенные изменения в код, включая переименование, перемещение и удаление классов, полей и методов. Если вы заметите, что эти изменения вызывают ошибки, вам нужно будет указать, какие части кода R8 не должен изменять, объявив их в правилах сохранения.
Распространенные сценарии, в которых требуются правила хранения
R8 идентифицирует и сохраняет все прямые вызовы в коде. Однако R8 не может обнаружить косвенное использование кода, поэтому может удалить код, необходимый для работы приложения, что приведет к сбоям. Чтобы R8 не удалял такой код, используйте правила сохранения. Ниже приведены распространенные ситуации, в которых могут потребоваться правила хранения.
- Код, доступ к которому осуществляется с помощью рефлексии. R8 не может определить, когда доступ к классам, полям или методам осуществляется с помощью рефлексии. Например, R8 не может определить метод, найденный по имени с помощью
Class.getDeclaredMethod(), или аннотацию, полученную с помощьюClass.getAnnotation(). В таких случаях R8 может переименовать эти методы и аннотации или полностью удалить их, что приведет к ошибкеClassNotFoundExceptionилиNoSuchMethodExceptionво время выполнения. - Код, вызываемый из Java Native Interface (JNI). Когда нативный код (C или C++) вызывает метод Java или Kotlin или код Java или Kotlin вызывает код C++ с помощью JNI, вызов основан на динамическом поиске строки по названию метода. R8 не может распознать динамический вызов метода на основе строки, поэтому оптимизация может нарушить работу кода.
Это не исчерпывающий список сценариев, в которых требуются правила хранения, но он охватывает большинство случаев, когда они могут понадобиться.
Если ваш код использует рефлексию или вызывается из JNI, вы можете добавить в него аннотации Jetpack Keep, а не писать правила вручную. Плагин Gradle генерирует правила сохранения из аннотаций во время сборки.
Как правила хранения влияют на оптимизацию
R8 – это оптимизатор, который анализирует код приложения, чтобы удалить неиспользуемый код, встроить методы, объединить классы и обфусцировать идентификаторы. Однако R8 может выполнять оптимизацию только в рамках заданной вами конфигурации.
Правила сохранения представляют собой явную инструкцию по ограничению оптимизации. Каждое правило keep ограничивает возможности R8 по преобразованию этой части базы кода. Ценность хорошо составленного правила хранения заключается в его специфичности:
Узкие правила сохранения обеспечивают максимальную оптимизацию. Настроив таргетинг только на точные точки входа, доступ к которым осуществляется динамически (например, рефлексивный конструктор или сериализованное поле), вы позволяете R8 оптимизировать остальную часть кода.
Общие правила сохранения препятствуют оптимизации. Объявление правил на уровне пакета или широких подстановочных знаков не позволяет R8 оптимизировать целые классы и все их элементы. R8 не может удалить, встроить, объединить или обфусцировать этот код.
Слишком широкие правила сохранения напрямую приводят к раздуванию двоичных файлов DEX, увеличению объема потребляемой памяти, замедлению запуска (TTID и TTFD) и повышению доли ошибок ANR. Не нужно сохранять классы "на всякий случай". Ваша цель – определить минимальный контракт, необходимый для динамического выполнения.
Чтобы найти слишком общие или ненужные правила сохранения, в том числе из сторонних библиотек, используйте анализатор конфигурации R8. В нем содержатся оценки сжатия, оптимизации и обфускации, которые показывают, какую часть кода может оптимизировать R8.
Как добавить правила хранения в приложение
Конфигурация правил сохранения зависит от версии AGP.
Код крупных приложений обычно распределен по нескольким модулям библиотек. В таких случаях часто лучше размещать правила сохранения вместе с кодом, к которому они применяются, в определенном модуле библиотеки. Основное отличие в поддержке правил сохранения для библиотек заключается в том, как вы объявляете эти правила в файле build.gradle.kts (или build.gradle) модуля библиотеки. Подробнее об оптимизации для авторов библиотек…
Для AGP версии 9.3 и более поздних
Добавьте правила в файл с суффиксом .keep в каталоге src/<variant>/keepRules. Пример: src/main/keepRules/custom-rules.keep. Обратите внимание, что использование обновленного DSL для AGP 9.3 и более поздних версий позволяет оптимизировать как код, так и ресурсы, и не требует явного определения файла правил сохранения Android по умолчанию (proguard-android-optimize.txt), поскольку он включен по умолчанию, если не указано иное.
Kotlin
android {
buildTypes {
release {
optimization {
enable = true // Enables code and resource optimizations.
}
}
}
}
Яркий
android {
buildTypes {
release {
optimization {
enable = true // Enables code and resource optimizations.
}
}
}
}
Пропустить правила сохранения платформы Android по умолчанию (расширенная настройка)
AGP предоставляет набор правил платформы Android по умолчанию. Чтобы исключить эти правила из конфигурации проекта и управлять всеми правилами сохранения самостоятельно, задайте для параметра optimization.keepRules.includeDefault значение false.
Kotlin
android {
buildTypes {
release {
optimization {
enable = true // Enables code and resource optimizations.
keepRules {
includeDefault = false // The file with optimization
// rules for the Android platform is included by
// default. To omit this file, set this option to false.
}
}
}
}
}
Яркий
android {
buildTypes {
release {
optimization {
enable = true // Enables code and resource optimizations.
keepRules {
includeDefault = false // The file with optimization
// rules for the Android platform is included by
// default. To omit this file, set this option to false.
}
}
}
}
}
Устаревший DSL для AGP версий ниже 9.3
Добавьте правила в файл proguard-rules.pro, расположенный в корневом каталоге модуля приложения. Если такого файла нет, создайте его. Чтобы применить правила из файла, его нужно объявить в файле build.gradle.kts (или build.gradle) на уровне модуля.
По умолчанию файл сборки также включает файл proguard-android-optimize.txt. Этот файл содержит правила, необходимые для большинства проектов для Android, поэтому его следует оставить в файле сборки. Этот файл основан на файле proguard-common.txt и содержит тот же контент.
Устаревший DSL (Kotlin)
android {
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
// Default file with default optimization rules.
getDefaultProguardFile("proguard-android-optimize.txt"),
...
)
}
}
}
Устаревший DSL (Groovy)
android {
buildTypes {
release {
minifyEnabled = true
shrinkResources = true
// Default file with default optimization rules.
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
...
}
}
}
Как добавить правило хранения
При добавлении правил хранения вы можете включить глобальные параметры, а также определить собственные правила хранения.
Глобальные параметры. Это общие директивы, которые влияют на то, как R8 работает со всей базой кода. Подробнее о глобальных настройках…
Правила сохранения. Их нужно тщательно продумать, чтобы найти баланс между максимальной оптимизацией кода и сохранением работоспособности приложения. Подробнее о том, как добавлять правила сохранения…
Сохранить правила для авторов библиотек
Ознакомившись с глобальными параметрами и синтаксисом правил сохранения, прочитайте статью Оптимизация для авторов библиотек.