Skip to content

R8 压缩与混淆

源:Android 官方文档 - 启用应用优化

R8 是 Android 的代码优化器,通过移除未使用的代码和资源、混淆代码、优化字节码等方式缩减应用大小并提升性能。

R8 优化效果

对用户的价值

  • 更快的启动速度
  • 提升渲染和运行时性能
  • 减少 ANR(应用无响应)
  • 更小的 APK/AAB 体积

对开发者

  • 降低用户下载门槛
  • 减少存储占用
  • 提高应用商店排名

启用 R8 优化

基础配置

在模块级 build.gradle.kts 中配置:

kotlin
android {
    buildTypes {
        getByName("release") {
            // 启用代码压缩、混淆和优化
            isMinifyEnabled = true
            
            // 启用资源缩减
            isShrinkResources = true
            
            // ProGuard 规则文件
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
}
groovy
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 - 项目特定规则

proguard
# 保留特定类
-keep class com.example.MyClass

# 保留类的所有成员
-keepclassmembers class com.example.MyClass {
    *;
}

# 保留注解
-keepattributes *Annotation*

# 保留泛型签名
-keepattributes Signature

# 保留异常信息
-keepattributes Exceptions

R8 工作流程

R8 执行以下优化步骤:

代码压缩(Shrinking)

  • 检测并移除未使用的类、字段、方法和属性
  • 移除未使用的库代码

代码混淆(Obfuscation)

  • 将类名、方法名、字段名缩短为无意义的字符(如 abc
  • 增加反编译难度

优化(Optimization)

  • 内联函数
  • 移除未使用的参数
  • 优化字节码

资源缩减(Resource Shrinking)

  • 移除未使用的资源文件
  • 合并重复资源

ProGuard 规则语法

保留规则

keep 系列指令

proguard
# 保留类和所有成员
-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>;
}

通配符

proguard
# ** 匹配任意包名
-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>;
}

常见场景规则

反射使用的类

proguard
# 保留通过反射访问的类
-keep class com.example.model.** { *; }

# 保留所有实体类
-keep class * implements java.io.Serializable { *; }

JNI 调用

proguard
# 保留 native 方法
-keepclasseswithmembernames class * {
    native <methods>;
}

枚举

proguard
# 保留枚举类
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

序列化

proguard
# 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();
}

注解

proguard
# 保留所有注解
-keepattributes *Annotation*

# 保留特定注解的类
-keep @androidx.annotation.Keep class *
-keepclassmembers class * {
    @androidx.annotation.Keep *;
}

资源缩减

启用资源缩减

资源缩减需要先启用代码压缩:

kotlin
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 中添加:

properties
android.r8.optimizedResourceShrinking=true

保留特定资源

创建 res/raw/keep.xml

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
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:discard="@layout/unused_layout" />

严格引用检查

默认情况下,R8 保留所有包含资源 ID 引用的资源。启用严格模式:

xml
<?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 工具还原混淆的堆栈:

bash
retrace.bat mapping.txt obfuscated_stacktrace.txt

上传 Mapping 文件

Google Play Console

发布 AAB 时自动上传,或手动上传 mapping 文件。

Firebase Crashlytics

kotlin
plugins {
    id("com.google.gms.google-services")
    id("com.google.firebase.crashlytics")
}

android {
    buildTypes {
        getByName("release") {
            firebaseCrashlytics {
                mappingFileUploadEnabled = true
            }
        }
    }
}
groovy
plugins {
    id 'com.google.gms.google-services'
    id 'com.google.firebase.crashlytics'
}

android {
    buildTypes {
        release {
            firebaseCrashlytics {
                mappingFileUploadEnabled true
            }
        }
    }
}

常见库的 ProGuard 规则

Retrofit

proguard
-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

proguard
-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

proguard
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase

Glide

proguard
-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 分析器:

BuildAnalyze 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 大小变化
  • 分析新增依赖的影响