R8 压缩与混淆
R8 是 Android 的代码优化器,通过移除未使用的代码和资源、混淆代码、优化字节码等方式缩减应用大小并提升性能。
R8 优化效果
对用户的价值:
- 更快的启动速度
- 提升渲染和运行时性能
- 减少 ANR(应用无响应)
- 更小的 APK/AAB 体积
对开发者:
- 降低用户下载门槛
- 减少存储占用
- 提高应用商店排名
启用 R8 优化
基础配置
在模块级 build.gradle.kts 中配置:
android {
buildTypes {
getByName("release") {
// 启用代码压缩、混淆和优化
isMinifyEnabled = true
// 启用资源缩减
isShrinkResources = true
// ProGuard 规则文件
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
}android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}⚠️ 建议:仅在 release 构建中启用,因为优化会增加构建时间并使调试困难。
ProGuard 配置文件
默认规则文件:
proguard-android.txt- 基础规则proguard-android-optimize.txt- 包含优化规则(推荐)
自定义规则文件:
proguard-rules.pro - 项目特定规则
# 保留特定类
-keep class com.example.MyClass
# 保留类的所有成员
-keepclassmembers class com.example.MyClass {
*;
}
# 保留注解
-keepattributes *Annotation*
# 保留泛型签名
-keepattributes Signature
# 保留异常信息
-keepattributes ExceptionsR8 工作流程
R8 执行以下优化步骤:
代码压缩(Shrinking):
- 检测并移除未使用的类、字段、方法和属性
- 移除未使用的库代码
代码混淆(Obfuscation):
- 将类名、方法名、字段名缩短为无意义的字符(如
a、b、c) - 增加反编译难度
优化(Optimization):
- 内联函数
- 移除未使用的参数
- 优化字节码
资源缩减(Resource Shrinking):
- 移除未使用的资源文件
- 合并重复资源
ProGuard 规则语法
保留规则
keep 系列指令:
# 保留类和所有成员
-keep class com.example.MyClass {
*;
}
# 仅保留类,不保留成员
-keep class com.example.MyClass
# 保留类名,但允许混淆成员
-keepnames class com.example.MyClass {
*;
}
# 保留类的特定成员
-keepclassmembers class com.example.MyClass {
public <methods>;
private <fields>;
}
# 保留所有公共类的公共方法
-keepclasseswithmembers class * {
public <methods>;
}通配符
# ** 匹配任意包名
-keep class com.example.** { *; }
# * 匹配单个包层级
-keep class com.example.* { *; }
# <init> 表示构造函数
-keep class com.example.MyClass {
public <init>(...);
}
# <methods> 表示所有方法
-keepclassmembers class com.example.MyClass {
public <methods>;
}
# <fields> 表示所有字段
-keepclassmembers class com.example.MyClass {
private <fields>;
}常见场景规则
反射使用的类:
# 保留通过反射访问的类
-keep class com.example.model.** { *; }
# 保留所有实体类
-keep class * implements java.io.Serializable { *; }JNI 调用:
# 保留 native 方法
-keepclasseswithmembernames class * {
native <methods>;
}枚举:
# 保留枚举类
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}序列化:
# Parcelable
-keep class * implements android.os.Parcelable {
public static final ** CREATOR;
}
# Serializable
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}注解:
# 保留所有注解
-keepattributes *Annotation*
# 保留特定注解的类
-keep @androidx.annotation.Keep class *
-keepclassmembers class * {
@androidx.annotation.Keep *;
}资源缩减
启用资源缩减
资源缩减需要先启用代码压缩:
android {
buildTypes {
getByName("release") {
isMinifyEnabled = true // 必须先启用
isShrinkResources = true // 然后启用资源缩减
}
}
}优化的资源缩减 AGP 8.1.2+
AGP 8.1.2+ 引入了优化的资源缩减功能:
AGP 9.0+ 自动启用
AGP 8.1.2 - 8.x 手动启用:
在 gradle.properties 中添加:
android.r8.optimizedResourceShrinking=true保留特定资源
创建 res/raw/keep.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@layout/used_by_reflection,@layout/used_by_native" />移除特定资源
创建 res/raw/keep.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:discard="@layout/unused_layout" />严格引用检查
默认情况下,R8 保留所有包含资源 ID 引用的资源。启用严格模式:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:shrinkMode="strict" />调试混淆后的代码
Mapping 文件
R8 生成 mapping.txt,记录原始名称到混淆名称的映射:
位置:app/build/outputs/mapping/release/mapping.txt
com.example.MyClass -> a:
void myMethod() -> a
int myField -> b还原堆栈跟踪
使用 retrace 工具还原混淆的堆栈:
retrace.bat mapping.txt obfuscated_stacktrace.txt上传 Mapping 文件
Google Play Console:
发布 AAB 时自动上传,或手动上传 mapping 文件。
Firebase Crashlytics:
plugins {
id("com.google.gms.google-services")
id("com.google.firebase.crashlytics")
}
android {
buildTypes {
getByName("release") {
firebaseCrashlytics {
mappingFileUploadEnabled = true
}
}
}
}plugins {
id 'com.google.gms.google-services'
id 'com.google.firebase.crashlytics'
}
android {
buildTypes {
release {
firebaseCrashlytics {
mappingFileUploadEnabled true
}
}
}
}常见库的 ProGuard 规则
Retrofit
-keepattributes Signature, InnerClasses, EnclosingMethod
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
-keepattributes AnnotationDefault
-keepclassmembers,allowshrinking,allowobfuscation interface * {
@retrofit2.http.* <methods>;
}
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-dontwarn javax.annotation.**
-dontwarn kotlin.Unit
-dontwarn retrofit2.KotlinExtensions
-dontwarn retrofit2.KotlinExtensions$*Gson
-keepattributes Signature
-keepattributes *Annotation*
-dontwarn sun.misc.**
-keep class com.google.gson.** { *; }
-keep class * implements com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# 保留数据模型类
-keep class com.example.model.** { *; }OkHttp
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabaseGlide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep class * extends com.bumptech.glide.module.AppGlideModule {
<init>(...);
}
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder {
*** rewind();
}分析优化效果
APK Analyzer
Android Studio 提供 APK 分析器:
Build → Analyze APK
查看:
- APK 总大小
- DEX 文件大小
- 资源文件大小
- 方法数量
- 引用数量
输出文件
构建后查看以下文件了解优化效果:
app/build/outputs/mapping/release/
├── configuration.txt # 完整的ProGuard配置
├── mapping.txt # 名称映射
├── seeds.txt # 保留的类和成员
├── usage.txt # 移除的代码
└── resources.txt # 资源缩减报告最佳实践
逐步启用:
- 先在 staging 构建中测试
- 验证应用功能正常
- 再应用到 release 构建
及时测试:
- 每次启用新规则后完整测试
- 重点测试反射、序列化、JNI 相关功能
保留 Mapping 文件:
- 每个发布版本都保存 mapping.txt
- 用于还原生产环境崩溃堆栈
使用库提供的规则:
- 大多数库会提供 ProGuard 规则
- AAR 库自动包含配置
- 查看库文档获取最新规则
避免过度保留:
- 只保留必要的类和成员
- 过多保留会减弱优化效果
监控 APK 大小:
- 定期检查 APK 大小变化
- 分析新增依赖的影响