混淆介绍:

在Android应用开发过程中,为了保护自己的代码不被轻易反编译和破解,通常会采用混淆技术对代码进行处理。混淆就是将代码中的变量、方法名等替换成基本字母组成的代码,例如一个方法名为`function()`,经过混淆后可能会被替换成`a()`。这样一来,即使代码被反编译,也很难还原出原始的代码结构。

混淆的好处:

1. 阅读性降低:经过混淆后的代码可读性较差,增加了破解难度。

2. 减少字节数:混淆后可以有效减少应用的体积,提高运行速度。

3. 提高安全性:混淆可以防止恶意攻击者通过逆向工程分析和修改代码。

然而,混淆也存在一定的缺点:

1. 测试不充分可能导致某些功能不能使用。在开发过程中需要确保混淆后的代码仍然能够正常运行和调试。

开启混淆:

在Android Studio的项目中,默认是关闭混淆的。要开启混淆,需要修改项目的配置文件。具体操作如下:

1. 打开项目的`build.gradle`文件(位于module层),找到`android`标签下的`buildTypes`,然后在其中的`release`标签下添加或修改以下配置:

```groovy

minifyEnabled false // 表示不开启混淆,改为true表示开启混淆

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' // 指定混淆规则文件

```

2. 打开项目的`proguard-rules.pro`文件(位于module层),在这个文件中添加自定义的混淆规则。例如:

```groovy

# 保留所有类不进行混淆

-keep class * {

public protected *;

}

# 保留所有实现了某个接口的类不进行混淆

-keep class * implements com.example.MyInterface {

public protected *;

}

```

3. 如果需要去掉没有引用的资源来减小应用体积,可以在`proguard-rules.pro`文件中添加以下配置:

```groovy

shrinkResources true // 启用资源压缩

```

需要注意的是,只有当混淆功能开启时(`minifyEnabled`设置为`true`),上述配置才会生效。

混淆配置文件不检查规则是否重复,如果两条规则冲突,则采用白名单的方式。例如,在设置了开启优化和不优化两个选项后,无论顺序如何,最终都会执行不优化的操作。

优化控制:

这个是用于控制混淆是否开启优化代码的功能,例如一些if/else语句可以被简化等操作。

```plaintext

# 不优化 -dontoptimize

# 代码循环优化次数,0-7,默认为5 -optimizationpasses 5

-dontoptimize

```

优化进阶:

开启优化后可以设置下面的规则,assumenosideeffects表示指定的代码无效,可以优化,最终效果表现为不执行。

```plaintext

# 混淆时所采用的优化规则 -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

# 关闭log -assumenosideeffects class android.util.Log { public static boolean isLoggable(java.lang.String, int); public static int v(...); public static int i(...); public static int w(...); public static int d(...); public static int e(...); }

```

基本混淆规则:

下面这些一般混淆规则都要加入,其中前两个在默认文件中已经配置:

```plaintext

# 包名不使用大小写混合 aA Aa -dontusemixedcaseclassnames

# 不混淆第三方引用的库 -dontskipnonpubliclibraryclasses

# 不做预校验 -dontpreverify

# 忽略警告 -ignorewarning

```

输出混淆记录:

混淆后由于阅读困难性提高,所以为了方便自己查阅,可以输出mapping对应文件。可以利用AndroidSDK\tools\proguard\bin中的proguardgui.bat打开混淆工具,利用retrace结合mapping和stacktrace调试遇到的错误。

混淆后生成映射文件的命令如下:

```java

# 混淆后生成映射文件 map 类名->转化后类名的映射 # 存放在app\build\outputs\mappingrelease中

-verbose

# 混淆前后的映射

-printmapping mapping.txt

# 输出apk包内所有class的内部结构

-dump class_files.txt

# 输出未混淆的类和成员

-printseeds seeds.txt

# 列出从apk中删除的代码

-printusage unused.txt

```

编写混淆规则的方法:

1. 如果混淆后报错,可以通过retrace找到错误的问题,然后编写规则去掉混淆。如果报错莫名其妙且报错的类没有混淆,可以采用以下极端方法:

```java

# 加入这条规则表示不混淆所有类及其中所有代码

-keep class *.** {*;}

```

2. 加了这条规则之后,还不能运行表示是其他问题,例如注解、内部类等。可以运行后,通过反编译寻找所有包名,记录下来,将上述规则改为:

```java

# 一个个去掉检查是否有报错

# 例如查到 -keep class com.** {*;} 加了就不报错,则可以继续一级级往下检查。但要注意,有时候可能是几个包混合问题。

```

3. 声明:原创文章,欢迎转载,请保留出处。有任何错误、疑问或者建议,欢迎指出。我的邮箱:Maxwell_nc@163.com。