当您使用默认设置启用应用优化时,R8 会执行广泛的优化,以最大程度地提高您的性能优势。R8 对代码进行了实质性修改,包括重命名、移动和删除类字段和方法。如果这导致错误,您需要通过编写保留规则来指定哪些代码部分应保持不变。
R8 可能会在以下情况下错误地移除或修改代码:
- 反射:通过反射访问的代码,例如使用
Class.forName()
或Method.invoke()
。R8 通常无法判断哪些类或方法会以这种方式访问。 - 序列化:序列化和反序列化所需的类或字段在 R8 看来可能未被使用(这是另一种形式的反射)。
- Java 本机接口 (JNI):从本机代码调用的 Java 方法。R8 不会分析本机代码以查看它可能回溯到 Java 的内容。
本页介绍如何限制 R8 优化的范围。要了解如何自定义保留哪些资源,请参阅添加资源保留规则。
在哪里添加保留规则
您应该将规则添加到模块根目录下的 proguard-rules.pro
文件中(该文件可能已经存在,如果不存在则创建)。要应用文件中的规则,您必须在模块级别的 build.gradle.kts
(或 build.gradle
)文件中声明该文件,如下面的代码所示
Kotlin
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" ) ... } } ... }
Groovy
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 通过分析应用的调用图来检测应用中需要保留的代码,该调用图从清单条目(如您的 activity 或 service)开始,并跟踪每个应用和库函数调用。R8 会删除未以这种方式直接引用的代码,如果执行的代码不属于此图(例如通过反射调用的代码),则可能导致问题。通过编写您自己的保留规则,您可以告知 R8 哪些代码需要保留在应用中。
要添加保留规则,请在 proguard-rules.pro
文件中添加一行 -keep
。
保留规则语法
保留规则通常遵循以下格式
-<KeepOption> [OptionalModifier,...] <ClassSpecification> [{ OptionalMemberSpecification }]
例如,要保留特定类及其所有成员,请使用以下内容
-keep class com.myapp.MyClass { *; }
有关更多示例,请参阅示例部分。
以下是保留规则组件的作用:
<KeepOption>
让您可以指定要保留的类的哪些方面保留选项 描述 -keep
保留类和
[{ 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 从本机代码调用 getter 或 setter。请注意,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>;
}