第2章 ProGuard配置文件的初始化与基本结构
2.1 配置文件的作用与位置
ProGuard 的混淆规则通过配置文件(通常为 proguard-rules.pro)声明。该文件位于模块根目录(Android 项目中为 app/ 目录),并在 build.gradle 的 minifyEnabled true 时被引用。配置文件采用逐行规则语法,支持注释、通配符和嵌套通配符,是控制混淆、优化、收缩行为的核心。
2.2 配置文件的典型骨架
# 示例:proguard-rules.pro 骨架
# 忽略指定警告
-dontwarn com.example.unused.**
# 保留整个类(包括所有成员)
-keep class com.example.payment.core.PaymentService { *; }
# 仅保留类的指定成员(类本身可混淆)
-keepclassmembers class com.example.payment.core.PaymentService {
public void processPayment(android.content.Context, double);
private int amount;
}
# 保留注解
-keepattributes *Annotation*
2.3 常用规则含义详解
| 规则 | 作用范围 | 保留内容 | 典型场景 |
|---|---|---|---|
| -dontwarn | 全局 | 抑制指定类的警告输出 | 引入第三方库时存在引用缺失的类 |
| -keep | 类 + 成员 | 类名及所有/指定成员不被混淆、不重命名 | 反射调用的核心类、JNI接口、序列化类 |
| -keepclassmembers | 仅成员 | 类成员(方法、字段)保留原方法名和字段名,类本身可混淆 | 保留支付接口回调方法、事件监听器 |
| -keepnames | 类名 | 仅保留类名,成员可混淆(缩减时仍保留) | 保留顶层类名便于日志分析 |
支付核心场景建议:对支付网关入口类(如
PaymentService、SignManager)使用 -keep 完整保护;对回调方法(如 onPaymentResult)使用 -keepclassmembers 保护方法签名,类名可被混淆以增加逆向难度。
2.4 各规则示例与说明
2.4.1 -dontwarn——抑制编译警告
当依赖的第三方库在编译期引用了某些不存在或不兼容的类时,ProGuard 会抛出警告并中断构建。-dontwarn 可明确告诉 ProGuard 忽略这些警告,让构建继续。
# 忽略 okhttp3 内部引用的 android.net.ssl 警告
-dontwarn okhttp3.internal.platform.**
# 忽略所有 com.example.legacy 包下的警告
-dontwarn com.example.legacy.**
使用风险:滥用
-dontwarn 可能隐藏真正的问题(如缺少必须的类导致运行时异常)。务必将警告级别调整为 warning,检查日志后再决定是否忽略。
2.4.2 -keep——完整保留类与成员
用于保护通过反射、JNI、XML布局或第三方框架调用的类。支付核心代码中,所有公开的 API 接口、签名验证类都应使用此规则。
# 保留 PaymentService 类及其所有成员
-keep class com.example.payment.core.PaymentService { *; }
# 保留指定包下所有类(不保留成员方法,除非显式声明)
-keep class com.example.payment.** { *; }
# 保留含特定注解的所有类
-keep @interface com.example.payment.annotation.PaymentApi
-keep @com.example.payment.annotation.PaymentApi class * { *; }
2.4.3 -keepclassmembers——仅保留成员
常用于保留通过反射调用的特定方法或字段,同时允许类名被混淆,从而兼顾保护逻辑与代码体积。例如支付回调处理器的处理入口。
# 保留 PaymentCallback 类中所有以 on 开头的方法
-keepclassmembers class com.example.payment.callback.PaymentCallback {
public void on*(*);
}
# 保留所有实现了 Serializable 的类的 serialVersionUID 字段
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
}
规则组合实战:在同一个项目中同时使用
-keep 保护顶层入口类,使用 -keepclassmembers 保护回调方法,使用 -dontwarn 解决第三方库兼容性问题。混用时注意优先级:-keep 覆盖 -dontwarn,但不会影响 -keepclassmembers。
2.5 配置调试与验证
混淆后可通过 mapping.txt 文件(位于 build/outputs/mapping/)验证规则是否生效。比较混淆前后的类名和方法名,确认支付核心代码未被重命名或移除。使用 -printusage 可输出被移除的代码,辅助排查过度收缩问题。
# 调试命令(在 gradle 禁用混淆后运行)
java -jar proguard.jar @proguard-rules.pro -printusage ./usage.txt -printmapping ./mapping.txt
2.6 常见错误与优化
- 警告:duplicate definition of class:检查是否对同一个类使用了多次
-keep,合并为单条规则。 - 运行时 NoSuchMethodException:确认使用了
-keepclassmembers保护了方法签名,且参数类型完整(包括全限定名)。 - 构建时间过长:避免对通配符
**使用过于宽泛的包路径,限定到支付核心包。 - APK 体积未减小:检查
-keep规则是否过多,考虑使用-keepclassmembers代替整类保护。
2.7 规则作用关系图
下图展示了 ProGuard 配置文件中最常用的三条规则如何作用于支付类及其成员,并最终影响混淆输出: