作者:小余同学
前言
使用java编写的源代码编译后生成了对于的class文件,但是class文件是一个非常标准的文件,市面上很多软件都可以对class文件进行反编译,为了我们app的安全性,就需要使用到Android代码混淆这一功能。针对 Java 的混淆,ProGuard 就是常用的混淆工具,且他不仅仅是混淆工具,它同时可以对代码进行 压缩、优化 、混淆。
下面我们来简单介绍下ProGuard工作流程。
1ProGuard 工作流程ProGuard工作过程包括四个步骤:shrink,optimize,obfuscate,preverigy。这四个步骤都是可选,但是顺序都是不变的。
- shrink:检测并删除项目中未使用到的类,字段,方法以及属性。
- optimize:优化字节码,移除无用指令,或者进行指令优化。
- obfuscate:代码混淆,将代码中的类,字段,方法和属性等名称使用无意义的名称进行表示,减少代码反编译后的可读性。
- preverify:针对 Java 1.6 及以上版本进行预校验, 校验 StackMap /StackMapTable 属性.在编译时可以关闭,加快编译速度。
2 Android中的代码优化以及混淆
Android构建中,在AGP3.4.0之前也是使用的ProGuard 进行代码优化混淆,但是在3.4.0之后,谷歌将这一工作赋予给了性能更佳的R8编译器。虽然摒弃了ProGuard,但是R8编译器还是兼容ProGuard的配置规则。使用R8编译器可以做以下优化:
- 1.代码缩减
- 2.资源缩减
- 3.代码混淆
- 4.代码优化
1.代码缩减:
代码缩减指的是:R8编译期智能检测代码中未使用到的类、字段、方法和属性等,并移除。
比如你项目中依赖了很多库,但是只使用了库里面少部分代码,为了移除这部分代码,R8会根据配置文件确定应用代码的所有入口点:包括应用启动的第一个Activity或者服务等,R8会根据入口,检测应用代码,并构建出一张图表,列出应用运行过程中可能访问的方法,成员变量和类等,并对图中没有关联到的代码,视为可移除代码。
如下图:
图中入口位置:MainActivity,整个调用链路中,使用到了foo,bar函数以及AwesomeApi类中的faz函数,所以这部分代码会被构建到依赖图中,而OkayApi类以及其baz函数都未访问到,则这部分代码就可以被优化。使用方式:
android {
buildTypes {
release {
...
minifyEnabled true
}
}
...
}
minifyEnabled 设置为true,会默认启用R8代码缩减功能。代码优化需要注意的两种情况:1.反射调用的情况2.JNI调用的情况R8并未对反射以及JNI等情况进行检测,如果配置文件中未处理,则这部分代码就会被丢弃,会出现NoClassFindException的异常,如何解决呢?
- 1.1:在配置文件中使用-keep对这部分类进行说明:
-keep public class MyClass
- 1.2:给需要保留的代码添加@keep注解
前提条件:1.声明了使用AndroidX 2.使用AGP默认的ProGuard文件。
R8配置文件
R8使用ProGuard 规则文件来决定哪部分代码需要保留,配置文件来源分为下面几个:
- 1.AndroidStudio:
位置:/proguard-rules.pro
说明:
创建新的模块时,会在当前模块目录下创建一个默认的:proguard-rules.pro 文件
- 2.AGP插件
位置:由AGP在编译时生成的proguard-android-optimize.txt说明:
Android Gradle 插件会生成 proguard-android-optimize.txt(其中包含了对大多数 Android 项目都有用的规则),并启用 @Keep* 注解。
编译后在\build\intermediates\proguard-files\目录下会生成3个文件:
proguard-android-optimize.txt-4.1.1:需要进行optimize代码优化的ProGuard配置文件。proguard-android.txt-4.1.1:表示不需要进行optimize代码优化的ProGu