最近在做Android应用的混淆,踩了一些坑,这里记录分享下个人的心得。
混淆介绍
首先先简单说一下什么是混淆和混淆的作用,其实这个搜索下可以找到一堆官方的说法等等,这里简单口语叙述一下,混淆就是把代码替换成a、b、c基本字母组成的代码,比如一个方法名为:function(),混淆后可能会被替换成a()。
混淆的好处:
- 代码混淆后阅读性降低,反编译后破译程序难度提高
- 混淆后字节数减少,减少了应用了体积
前者只能说有一点作用,后者则需要看代码的数量
当然不能忽视混淆的缺点:
- 混淆后,测试不充分可能导致某些功能不能使用
开启混淆
混淆在Android Studio的项目中默认是关闭的,其中控制开关和规则配置文件分别由项目moudle中的build.gradle和proguard-rules.pro控制,如下图所示:
其中build.gradle中
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
其中
minifyEnabled false
表示不开启混淆,可以改为
minifyEnabled true
开启混淆,开启混淆后可以添加一句:
shrinkResources true
表示去掉没有引用的资源,可以减少应用的体积,但这个只有在混淆开启后才有效。
混淆规则文件
可以从上述的代码看出,Android自带一个混淆规则文件:
proguard-android.txt
这个文件在SDK目录下,里面有一些默认自带的规则,而我们今天需要配置的自定义配置的文件,即上面所述的
proguard-rules.pro
混淆规则基本语法
混淆文件采用白名单法,意思是不在白名单里面的都要混淆。
混淆规则的基本符号:
# 代表行注释符
- 表示一条规则的开始
一般规则用连起来单词表示,主要有:
keep 保留,例如keepattributes:表示保留属性
dont 不要,例如dontwarn:表示不要提示警告
ignore 忽略,例如ignorewarning:表示忽略警告
混淆配置文件不检查规则是否重复,如果两条规则冲突,则采用白名单的,比如设置了开启优化和不优化两个选项后,无论顺序,最终都会执行不优化的操作。
优化控制
这个是用于控制混淆是否开启优化代码,例如一些if/else语句可以被简化等这些操作:
# 不优化
-dontoptimize
# 代码循环优化次数,0-7,默认为5
-optimizationpasses 5
值得注意的是默认混淆配置文件开启了-dontoptimize
。
优化进阶
开启优化后可以设置下面的规则,assumenosideeffects表示指定的代码无效,可以优化,最终效果表现为不执行。
# 混淆时所采用的优化规则
-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(...);
}
基本混淆规则
下面这些一般混淆规则都要加入,其中前两个在默认文件中已经配置:
# 包名不使用大小写混合 aA Aa
-dontusemixedcaseclassnames
# 不混淆第三方引用的库
-dontskipnonpubliclibraryclasses
# 不做预校验
-dontpreverify
# 忽略警告
-ignorewarning
输出混淆记录
混淆后由于阅读困难性提高,所以为了方便自己查阅,可以输出mapping对应文件,可以利用AndroidSDK\tools\proguard\bin中的proguardgui.bat打开混淆工具,利用retrace结合mapping和stacktrace调试遇到的错误
# 混淆后生产映射文件 map 类名->转化后类名的映射
# 存放在app\build\outputs\mapping\release中
-verbose
# 混淆前后的映射
-printmapping mapping.txt
# apk 包内所有 class 的内部结构
-dump class_files.txt
# 未混淆的类和成员
-printseeds seeds.txt
# 列出从 apk 中删除的代码
-printusage unused.txt
混淆规则编写方法
如果混淆后报错,通过retrace后找到错误的问题后可以直接编写规则来去掉混淆,但是如果报的错误莫名其妙,而且报错的类没有混淆,那么你可以采用极端的方法:
加入下面规则:
-keep class *.** {*;}
这条规则表示不混淆所有类及其中所有代码,加了这条规则之后,
还不能运行表示是其他问题,例如注解,内部类等等,
可以运行后,可以通过反编译,寻找所有包名,记录下来,把上述规则改为:
-keep class android.** {*;}
-keep class com.** {*;}
-keep class io.** {*;}
-keep class org.** {*;}
...
一个个去掉检查是否有报错,例如查到
-keep class com.** {*;}
加了就不报错,则可以继续一级级往下检查。
但要注意,有时候可能是几个包混合问题。
声明
原创文章,欢迎转载,请保留出处。
有任何错误、疑问或者建议,欢迎指出。
我的邮箱:Maxwell_nc@163.com