前言
大家在打包正式apk包,发布应用市场时,都会开启混淆配置,这样可以优化包体积大小,而且能增加别人反编译的难度,有没有人和我一样,对于混淆只停留在使用层面上,发布release包时打开minifyEnable设置为true,然后添加混淆时到网上copy一份混淆配置,就ok了,这些配置到底是什么意思呢?以及混淆在打包过程中处于哪个阶段呢?sdk打包成aar如何配置混淆呢?下文会告诉你答案。
一、apk打包的编译过程,认识D8和R8。
我们知道,从java代码经过编译过程,变成dex文件,是经过一系列的任务处理的。
在gradle3.0版本之后,引入了d8处理器,java代码由Javac处理成.class文件,再经过proguard混淆优化,变成优化过的.class文件,最后由d8处理成最终的dex文件。
1.什么D8?
D8是gradle编译时的task的名字的简称,主要是处理字节码脱糖和dx打包。我们知道在Java1.8之后,可以使用lamada语法糖,可以让代码更加的简洁,d8的任务是将art不认识的java8字节码处理成编译器认识的java低版本的字节码指令,然后由DX处理成dex文件。
2.什么是R8?
R8是将Proguard任务和D8任务合并成一个task
在gradle3.2之后引入R8编译,3.4版本之后将R8作为默认的编译处理器。
R8优化了编译速度,同时减小apk的体积,它主要做以下事情:
1.将D8和Proguard两个过程融合成一个任务,减少了编译步骤,编译速度更快。
2.缩减了代码,将没有使用的代码移除掉,减小了apk包的体积。
3.缩减资源文件,将重复和无用的资源文件移除
4.如果开启了multidex开关,会进行dex分包处理。
二、组件化aar混淆方案
在创建Module时,在build.gradle中会自动生成两个混淆文件
defaultConfig {
...
consumerProguardFiles 'consumer-rules.pro'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
1.proguardFiles和consumerProguardFiles的区别:
在打包发布aar文件时,开启minifyEnabled=true,proguardFiles会生效,此时别人反编译代码,看到的是已混淆的文件。
consumerProguardFiles是依赖主项目时生效的文件,在此文件中你可以添加对外暴露的类不混淆的代码,它会作用于整个app中。
proguardFiles不会打包进aar中,而consumerProguardFiles会打包进aar中。
2.添加混淆配置
方案一:
将aar的反混淆代码写到宿主的proguardFiles中,这样的好处是统一维护,不好的地方在于如果需要移除某个aar时,相应的要移除它的反混淆的代码。
方案二:
在aar中的consumerProguardFiles添加混淆配置,宿主app不需要收到添加。这样做的好处是不需要依赖主项目,最大限度做到解藕的目的。
三、自定义混淆规则介绍
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
在app的gradle文件中默认有两个混淆文件,其中proguard-android-optimize文件位于SDK内tools/proguard文件夹中,配置了默认不需要混淆的代码,比如Android的四大组件,以及继承view的构造方法等。
proguard-rules.pro配置自定义的混淆规则。
1.常见的混淆命令说明
命令 | 作用 |
---|---|
-keep | 防止类和成员被移除或者被重命名 |
-keepnames | 防止类和成员被重命名 |
-keepclassmembers | 防止成员被移除或者被重命名 |
-keepnames | 防止成员被重命名 |
-keepclasseswithmembers | 防止拥有该成员的类和成员被移除或者被重命名 |
-keepclasseswithmembernames | 防止拥有该成员的类和成员被重命名 |
2.常用的混淆规则举例
-
不混淆某个类
-keep public class name.huihui.example.Test { *; }
-
不混淆某个包所有的类
-keep class name.huihui.test.** { *; }
-
不混淆某个类的子类
-keep public class * extends name.huihui.example.Test { *; }
-
不混淆所有类名中包含了“model”的类及其成员
-keep public class **.*model*.** {*;}
-
不混淆某个接口的实现
-keep class * implements name.huihui.example.TestInterface { *; }
-
不混淆某个类的构造方法
-keepclassmembers class name.huihui.example.Test { public <init>(); }
-
不混淆某个类的特定的方法
-keepclassmembers class name.huihui.example.Test { public void test(java.lang.String); }
参考资料