一、基础概念
1. 混淆工具
- R8:Android Gradle Plugin 3.4+ 默认,替代旧版 ProGuard,兼顾压缩、混淆、资源精简、Dex 优化,编译更快。
- ProGuard:旧版混淆工具,现已废弃,仅兼容老项目。混淆三件事:
- 压缩 (Shrink) :删除未使用类、方法、字段;
- 混淆 (Obfuscate) :类 / 方法 / 字段改名成 a、b、c 缩短名称,反编译阅读困难;
- 优化 (Optimize) :精简代码逻辑、内联方法、删除无用分支。
2. 开启混淆开关(build.gradle Module)
gradle
arduino
android {
buildTypes {
release {
minifyEnabled true // 开启混淆+代码压缩
shrinkResources true // 开启资源压缩(依赖minifyEnabled)
// 混淆规则文件
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled false // debug一般关闭,方便调试
}
}
}
proguard-android-optimize.txt:系统自带优化混淆规则;proguard-rules.pro:自定义项目混淆规则。
二、核心混淆指令大全(最常用)
1. 保留类不被混淆
proguard
scala
# 保留指定类完整不混淆
-keep class com.xxx.bean.User
# 保留包下所有类,不混淆
-keep class com.xxx.bean.** { *; }
# 保留父类是XXX的所有子类
-keep class * extends android.app.Activity
# 保留实现某接口的所有类
-keep class * implements android.view.View.OnClickListener
2. 保留类中成员(方法 / 字段)
proguard
csharp
# 保留类所有成员
-keep class com.xxx.bean.User { *; }
# 只保留public方法和字段
-keep public class com.xxx.bean.User {
public <fields>;
public <methods>;
}
# 保留所有构造方法
-keep class com.xxx.bean.User {
<init>;
}
# 保留native方法
-keepclasseswithmembernames class * {
native <methods>;
}
3. 保留类名,允许混淆内部方法
proguard
kotlin
-keepnames class com.xxx.bean.User
4. 保留反射相关(重中之重)
如果代码用反射调用类 / 方法,混淆后名称改变会报错,必须保留:
proguard
csharp
# 保留反射用到的类
-keep class com.xxx.reflect.ReflectUtil { *; }
# 保留反射调用的方法
-keep class com.xxx.bean.User {
void setName(java.lang.String);
java.lang.String getName();
}
5. 不压缩、不删除(仅改名)
-dontshrink:关闭代码压缩; -dontoptimize:关闭代码优化; -dontobfuscate:完全关闭混淆(仅打包不改名)。
6. 忽略警告(第三方包大量告警时使用)
proguard
bash
# 忽略所有警告(不推荐全局使用,优先精准忽略)
-dontwarn **
# 精准忽略某包警告
-dontwarn okhttp3.**
7. 输出映射文件(用于线上崩溃堆栈还原)
proguard
shell
# 输出混淆映射文件,路径 build/outputs/mapping/release/mapping.txt
-printmapping mapping.txt
8. 泛型、注解、枚举保留
proguard
csharp
# 保留注解
-keepattributes *Annotation*
# 保留泛型、异常行号、签名
-keepattributes Signature,Exceptions,SourceFile,LineNumberTable
# 枚举必须保留
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.Str
三、Android 四大组件固定混淆规则(必须加)
系统通过反射启动四大组件,一旦混淆改名会直接崩溃:
proguard
scala
# Activity
-keep public class * extends android.app.Activity
-keep public class * extends androidx.appcompat.app.AppCompatActivity
# Service
-keep public class * extends android.app.Service
# BroadcastReceiver
-keep public class * extends android.content.BroadcastReceiver
# ContentProvider
-keep public class * extends android.content.ContentProvider
# 所有组件的构造方法、生命周期方法
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
四、View 自定义控件规则
XML 布局中通过 class="xxx.xxxView" 反射创建,不能混淆:
proguard
csharp
# 保留所有自定义View
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
# 布局onClick点击方法(xml android:onClick)
-keepclassmembers class * {
void *(android.view.View);
}
五、JSON 实体类必加规则(Gson/Jackson/FastJson)
实体类字段被混淆后,序列化 / 反序列化字段名不匹配,解析失败:
通用方案:所有实体类统一保留
proguard
csharp
# 假设所有bean放在 com.xxx.bean 包
-keep class com.xxx.bean.** { *; }
Gson 专用规则
proguard
diff
-keepattributes Signature
-keepattributes *Annotation*
# 保留序列化实体
-keep class com.google.gson.** {*;}
-keep class com.xxx.bean.** {
<fields>;
}
六、混淆常见踩坑点 & 注意事项
1. 反射相关类 / 方法不保留 → 运行崩溃
场景:Gson 解析、EventBus、JS 交互、动态跳转、反射工具类。解决方案:精准 -keep 对应类和方法。
2. XML 自定义 View、onClick 方法被混淆
布局反射创建 View、点击方法找不到,闪退。解决方案:添加自定义 View 专属 keep 规则。
3. 第三方 SDK 忘记加混淆规则
现象:打包成功,运行报 NoSuchMethod / ClassNotFound。解决方案:去 SDK 官方文档复制配套混淆规则。
4. 枚举、Parcelable Creator 丢失
序列化传参直接报错,必须单独保留枚举与 CREATOR 字段。
5. 线上崩溃堆栈看不懂
原因:没开启 printmapping 输出 mapping.txt,无法还原混淆后的类名。解决方案:打包 release 后保存 mapping 文件,用于崩溃日志还原。
6. 开启资源压缩后图片 / 布局丢失
gradle
arduino
shrinkResources true
未引用资源会被删除,若代码动态加载资源,添加资源保留:
proguard
bash
# 保留指定资源
-keepresource xml layout/main
7. 混淆后调试困难
- debug 环境关闭混淆;
- release 如需调试,可临时添加
-dontobfuscate关闭混淆。
8. 组件、Service、BroadcastReceiver 类名混淆
AndroidManifest 中写死类全名,混淆改名后系统找不到组件,直接闪退,四大组件必须全部 keep。
七、AGP 8.x/ 9.x 新版 rules.keep 完整说明(纠正误区:不是替代 proguard-rules.pro)
1、先澄清核心误区
- rules.keep 不是放全部混淆规则的文件 ,它只放R8 专属轻量 keep 保留规则;
- 传统
proguard-rules.pro依然完全生效,两者是互补关系,不是替换; - 你看到的
rules.keep是 Android Studio 新版模板自动生成的R8 专用保留规则文件 ,语法简化、仅支持-keep系列指令,不支持-dontwarn、-printmapping、优化开关等完整 ProGuard 指令。
2、三种规则文件完整区分(AGP 8+ 共存)
1. proguard-rules.pro(传统全量混淆文件,项目主规则)
- 支持全部 ProGuard/R8 语法 :
-keep/-dontwarn/-printmapping/-keepattributes/-dontoptimize等; - 放项目全局通用规则:四大组件、Gson 实体、第三方 SDK、JNI、输出 mapping、全局警告忽略;
- build.gradle 显式注册:
gradle
java
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
2. rules.keep(新版轻量 R8 keep 专用文件)
特点
- 仅支持
keep/keepclassmembers/keepnames等保留类规则; - 不支持全局配置、警告忽略、映射文件、优化开关;
- 无需在 gradle 手动注册,R8 自动读取模块下
src/main/rules.keep; - 语法更简洁,只写「哪些类不能被删 / 改名」,适合放业务 Bean、自定义 View、反射类;
- 推荐放纯业务自定义类 keep 规则,把反射 / 序列化类抽离到这里,精简 proguard-rules.pro。
示例 rules.keep 内容(只写 keep):
plaintext
csharp
# 网络实体
-keep class com.xxx.bean.** { *; }
# 自定义View
-keep class com.xxx.view.** {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
}
# JS交互类
-keep class com.xxx.js.JsInterface { <methods>; }
3. consumer-rules.pro(仅 Library 模块生效)
给第三方库对外 API 保留规则,App 模块不读取,库打包时自动传递给依赖它的 App。
3、两者分工最佳实践(新版项目标准分层)
1. rules.keep 只放:纯 keep 保留规则(自己写的业务类)
适合:
- 所有 JSON 实体 Bean
- 自定义 View、自定义注解类
- JS 交互、JNI 交互类
- ARouter/EventBus 反射相关类、接口实现
- 自己手写反射用到的类、方法
2. proguard-rules.pro 放:全局配置、框架、系统规则、杂项指令
必须放这里(rules.keep 不支持):
- 全局属性保留:
-keepattributes *Annotation*,Signature,LineNumberTable - 输出 mapping 日志:
-printmapping mapping.txt - 第三方 SDK 忽略警告:
-dontwarn okhttp3.** - 优化开关:
-dontshrink/-dontobfuscate(调试临时用) - 系统通用基础规则(四大组件、Parcelable、枚举、native 通用模板)
4、底层执行顺序
- SDK 默认规则
proguard-android-optimize.txt最先加载; - 自动读取
rules.keep所有 keep 规则; - 再加载手动注册的
proguard-rules.pro; - 规则冲突以后加载的为准(proguard-rules 优先级高于 rules.keep)。
5、常见疑问解答
1. 能不能只写 rules.keep,删掉 proguard-rules.pro?
不可以 。rules.keep 不支持 -dontwarn、-keepattributes、映射文件、全局优化配置,删掉会出现:
- 注解 / 泛型被删除,Gson、反射直接报错;
- 第三方库大量编译警告;
- 无法生成 mapping.txt,线上崩溃堆栈无法还原。
2. 老项目没有 rules.keep 需要新建吗?
可选。
- 不想拆分:全部规则仍写在 proguard-rules.pro 完全兼容;
- 想分层管理:新建
src/main/rules.keep,把业务类 keep 迁移进去,精简主混淆文件。
3. 自己写的类、接口、方法放哪里 keep?
- 纯
-keep保留规则 → 放到rules.keep(整洁分层); - 需要搭配
-dontwarn、全局属性、映射配置 → 留在proguard-rules.pro。
4. 混淆失效、类被删除排查
- 反射类只写在 rules.keep 没问题;
- 如果需要保留泛型 / 注解,必须在 proguard-rules.pro 添加
-keepattributes Signature,*Annotation*; - 第三方 SDK 警告报错,只能在 proguard-rules 加
-dontwarn。
6、最简分层模板示例
src/main/rules.keep(只放业务 keep)
plaintext
csharp
# 网络、本地存储实体
-keep class com.xxx.bean.** { *; }
# 自定义控件
-keep class com.xxx.widget.** {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
}
# EventBus 订阅方法
-keepclassmembers class ** {
@org.greenrobot.eventbus.Subscribe <methods>;
}
# JS交互
-keep class com.xxx.bridge.JsApi { <methods>; }
proguard-rules.pro(全局配置 + 系统通用规则)
proguard
scala
# 输出混淆映射
-printmapping mapping.txt
# 保留注解、泛型、行号
-keepattributes *Annotation*,Signature,Exceptions,SourceFile,LineNumberTable
# 四大组件通用
-keep public class * extends android.app.Activity
-keep public class * extends androidx.appcompat.app.AppCompatActivity
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
# Parcelable
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# JNI native
-keepclasseswithmembernames class * {
native <methods>;
}
# 第三方库忽略警告
-dontwarn okhttp3.**
-dontwarn retrofit2.**
7、总结一句话
rules.keep 是 AGP8+ 新增的轻量专用 keep 规则文件 ,只用来存放你自己业务类的保留指令;传统 proguard-rules.pro 依然是主混淆配置文件,承载全局属性、警告、映射、系统组件、第三方 SDK 完整配置,两者配合使用,不是替换关系。