При включении оптимизации приложения с настройками по умолчанию R8 выполняет обширную оптимизацию, чтобы максимизировать ваши преимущества производительности. R8 вносит существенные изменения в код, включая переименование, перемещение и удаление полей и методов классов. Если это приводит к ошибкам, вам необходимо указать, какие части кода следует оставить, написав правила keep .
R8 может некорректно удалить или изменить код в следующих ситуациях:
- Отражение: код, доступ к которому осуществляется с помощью отражения, например, с помощью
Class.forName()
илиMethod.invoke()
. R8 обычно не может определить, к каким классам или методам будет осуществляться доступ таким образом. - Сериализация: классы или поля, необходимые для сериализации и десериализации, могут показаться неиспользуемыми в R8 (это еще одна форма рефлексии).
- Java Native Interface (JNI): методы Java, вызываемые из собственного кода. R8 не анализирует собственный код, чтобы увидеть, что он может вызвать обратно в Java.
На этой странице описывается, как ограничить масштабы оптимизаций R8. Чтобы узнать, как настроить, какие ресурсы сохраняются, см. раздел Добавить правила сохранения для ресурсов .
Где добавить правила хранения
Вам следует добавить свои правила в файл proguard-rules.pro
, расположенный в корневом каталоге модуля (файл может уже быть там, но если его там нет, создайте его). Чтобы применить правила в файле, вы должны объявить файл в файле build.gradle.kts
(или build.gradle
) на уровне модуля, как показано в следующем коде:
Котлин
android { buildTypes { release { isMinifyEnabled = true isShrinkResources = true proguardFiles( // Default file with default optimization rules. getDefaultProguardFile("proguard-android-optimize.txt"), // File with your custom rules. "proguard-rules.pro" ) ... } } ... }
Круто
android { buildTypes { release { minifyEnabled true shrinkResources true proguardFiles( // Default file with default optimization rules. getDefaultProguardFile('proguard-android-optimize.txt'), // File with your custom rules. 'proguard-rules.pro' ) ... } } // ... }
По умолчанию ваш скрипт сборки также включает файл proguard-android-optimize.txt
. Этот файл содержит правила, которые требуются для большинства проектов Android, поэтому его следует сохранить в скрипте сборки.
Как написать правила хранения
Во время компиляции приложения R8 определяет, какой код необходимо сохранить в приложении, анализируя граф вызовов вашего приложения, который начинается с записей манифеста (например, ваши действия или службы) и прослеживается через каждый вызов функции приложения и библиотеки. R8 удаляет код, на который нет прямых ссылок таким образом, что может вызвать проблемы, если исполняемый код не является частью этого графа, например, код, вызванный отражением. Написав собственные правила сохранения, вы можете сообщить R8 о коде, который необходимо сохранить в приложении.
Чтобы добавить правило сохранения, добавьте строку -keep
в файл proguard-rules.pro
.
Сохранить синтаксис правила
Правила хранения обычно имеют следующий формат:
-<KeepOption> [OptionalModifier,...] <ClassSpecification> [{ OptionalMemberSpecification }]
Например, чтобы сохранить определенный класс и всех его членов, используйте следующее:
-keep class com.myapp.MyClass { *; }
Дополнительные примеры см. в разделе «Примеры» .
Вот что делают компоненты правила сохранения:
<KeepOption>
позволяет указать, какие аспекты класса следует сохранить:Сохранить вариант Описание -держать
Сохраните класс и члены, перечисленные в
[{ OptionalMemberSpecification }]
.-keepclassmembers
Разрешить оптимизацию класса; если класс сохранен, сохранить члены, перечисленные в
[{ OptionalMemberSpecification }]
.-keepnames
Разрешить удаление класса и членов, но не запутывать и не изменять их иными способами.
-keepclassmembernames
Разрешить удаление класса и членов, но не запутывать и не изменять членов другими способами.
-keepclasseswithmembers
Не допускается удаление или запутывание классов, если члены соответствуют указанному шаблону.
Мы рекомендуем в основном использовать
-keepclassmembers
, поскольку он обеспечивает большую часть оптимизаций, а затем-keepnames
при необходимости.-keep
не допускает никакой оптимизации, поэтому старайтесь использовать его экономно.[OptionalModifier],...]
позволяет перечислить ноль или более модификаторов языка Java для класса, напримерpublic
илиfinal
.<ClassSpecification>
позволяет указать, к какому классу (или к какому суперклассу или реализованному интерфейсу) должно применяться правило сохранения. В простейшем случае это один полностью определенный класс.[{ OptionalMemberSpecification }]
позволяет вам фильтровать поведение сохранения только для классов и методов, соответствующих определенным шаблонам. Обычно это рекомендуется в большинстве правил сохранения, чтобы предотвратить сохранение большего, чем предполагалось.
Сохраните примеры правил
Вот несколько примеров хорошо продуманных правил хранения.
Построить подкласс
Это правило сохранения упаковано внутри androidx.room:room-runtime
для сохранения конструкторов базы данных , созданных с помощью отражения .
-keep class * extends androidx.room.RoomDatabase { void <init>(); }
Отражение от Android Framework ObjectAnimator
Это правило сохранения упаковано внутри androidx.vectordrawable:vectordrawable-animated
, чтобы ObjectAnimator
мог вызывать геттеры или сеттеры из собственного кода с помощью JNI. Обратите внимание, что более новые системы анимации в Compose не требуют правил сохранения, подобных этому, это просто пример структуры правила.
-keepclassmembers class androidx.vectordrawable.graphics.drawable.VectorDrawableCompat$* {
void set*(***);
*** get*();
}
Регистрация JNI
Это правило сохранения упаковано внутри androidx.graphics:graphics-path
, используется для сохранения собственных методов. Это может быть необходимо, если ваша библиотека вручную регистрирует собственные методы с помощью env->RegisterNatives()
.
-keepclasseswithmembers class androidx.graphics.path.** {
native <methods>;
}