Android打包里说的“混淆包”,通常不是一个全新的APK&AAB,而是指开启混淆后构建产物里配套产生的一组文件,核心是:

mapping.txt:混淆映射文件

它记录了:

原始类名/方法名/字段名 -> 混淆后的名字

比如:

com.xxx.user.UserProfilePresenter -> a.b.c:
    void loadUserInfo() -> a
    java.lang.String userId -> b

线上崩溃日志里可能看到:

at a.b.c.a(SourceFile:23)

拿到mapping.txt后,就可以还原成:

at com.xxx.user.UserProfilePresenter.loadUserInfo(UserProfilePresenter.java:23)

1. 为什么Android要混淆?

Android打包时,代码最终会变成.dex文件。别人可以通过反编译工具看到比较多的类名、方法名、业务逻辑。 所以Release包通常会开启:

minifyEnabled true

Android Release构建通常通过R8/ProGuard/DexGuard做三件事:

  1. 压缩Shrink 删除静态分析认为没有使用的类和方法。
  2. 优化Optimize 内联方法、删除无效代码、合并逻辑等。
  3. 混淆Obfuscate 缩短类名和方法名。例如: Ortsession.run() 可能变成: a.b()

普通Java调用会同步修改调用方,因此通常没问题。但下面这些动态调用无法通过静态分析识别:

  • JNI/native调用
  • 反射
  • JSON序列化
  • JavaScript接口
  • XML中引用的类
  • 通过字符串拼接得到的类名或方法名

这类代码通常需要-keep规则


2. 混淆包里最重要的文件:mapping.txt

开启混淆后,一般会在类似目录生成:

app/build/outputs/mapping/release/mapping.txt

有些项目也会把它打进一个zip,统称为:

mapping.zip
progurad.zip
symbol.zip
混淆包

不同公司叫法不同,但是核心都是为了保存Release包和mapping文件的对应关系。


3. 常见的混淆相关文件

开启R8/ProGuard后,常见有这些文件:

mapping.txt

最重要,记录原始名字和混淆名字的映射。

usage.txt

记录哪些类、方法、字段被删除了。

seeds.txt

记录哪些类和成员被保留,没有被混淆。

configuration.txt

记录最终生效的混淆规则。


4. 项目中怎么开启?

典型配置

android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true

            proguardFiles getDefaultProguardFile(
                'proguard-android-optimize.txt'
            ), 'proguard-rules.pro'
        }
    }
}

minifyEnabled true :开启代码压缩、优化、混淆。 shrinkResources true:删除未使用的资源,比如无用图皮、layout、string。 proguard-rules.pro:自己写的保留规则。

5. 为什么有些类不能被混淆?

因为有些代码依赖 反射、注解、序列化、JNI、路由、WebView JSBridge 等机制。

比如Gson:

class User {
    String userName;
    int age;
}

如果字段被混淆:

userName -> a
age -> b

服务端返回:

{
  "userName": "Tom",
  "age": 18
}

Gson就找不到字段了。

所以要么加注解:

@SerializedName("userName")
String userName;

要么写keep规则:

-keep class com.xxx.model.** { *; }

6. R8和ProGuard是什么关系?

现在Android Gradle Plugin默认使用的是R8。

ProGuard:老一代混淆/压缩工具 R8:Google新一代替代工具

但很多文件和配置名字还是叫:

proguard-rules.pro
proguardFiles

所以很多人习惯说“ProGuard混淆”。 实际上现在大多数Android项目是:

R8执行混淆+使用ProGuard规则语法