混淆介绍:
在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。