ProGuard是最受欢迎的Java字节码优化器。 它使您的Java和Android应用程序缩小了90%,速度提高了20%。 ProGuard还通过模糊类,字段和方法的名称来提供对逆向工程的最小保护。本篇将从Android apk混淆和jar混淆两个方面进行展开。
我们通常说的proguard包括四个功能,shrinker(压缩), optimizer(优化),obfuscator(混淆),preverifier(预校验)。这里附上官网的一张流程图:
- shrink: 检测并移除没有用到的类,变量,方法和属性;
- optimize: 优化代码,非入口节点类会加上private/static/final, 没有用到的参数会被删除,一些方法可能会变成内联代码。
- obfuscate: 使用短又没有语义的名字重命名非入口类的类名,变量名,方法名。入口类的名字保持不变。
- preverify: 预校验代码是否符合Java1.6或者更高的规范
无论是给apk添加混淆也好还是给jar文件或者aar文件添加混淆也好,底层其实都是依赖proguard.jar这个jar包来实现的,这个jar包安卓开发者可以在Android SDK根目录\tools\proguard\lib下找到,其他开发者可以在Proguard官网找到下载方式,以及官方说明文档。
如果有Android SDK的同学可以在{ANDROID_SDK_ROOT}/tools/proguard/lib/目录下找到proguard.jar这个jar包。或者,也可以在{ANDROID_SDK_ROOT}/tools/proguard/bin目录下直接使用脚本执行命令。
proguard.jar的使用:
使用proguard.jar添加混淆大致分为三种方式,
- 直接执行命令:
java -jar proguard.jar options ...
- 配置文件方式:
我们也可以把proguard的参数写到一个配置文件中,比如说proguard.cfg。那我们的命令可以这样写:
java -jar proguard.jar @proguard.cfg - 配置文件与配置参数混用:
java -jar proguard.jar @proguard.cfg -verbose
配置文件格式:
- 配置文件中 # 放在行首,用来做注释;
- 单词之间多余的空格或分隔符会被忽略;
- 如果文件名包含空格或者其它特殊符号,应当用单引号或者双引号括起来;
- 配置参数的顺序与混淆结果是没有关系的(不绝对,-injars和-outjars是有先后之分的)
一、Android Studio apk混淆
在AndroidStudio中借助SDK中自带的Proguard工具,只需要修改build.gradle中的一行配置即可为apk添加混淆。
可以看到minifyEnabled默认为false,我们只需将该设置改为true即可在打release包时候自动加载"proguard-android.txt"和"proguard-rules.pro"文件中的混淆规则为apk添加混淆处理。“proguard-rules.pro”文件大家都很熟悉,就是创建项目时候as默认为我们生成的。"proguard-android.txt"其实是Android Studio为我们配置的一些有关Android的默认混淆配置,位于Android SDK根目录\tools\proguard\proguard-android.txt。
proguard-android.txt这里面是一些比较常规的不能被混淆的代码规则。我们可以找到该文件,看看里面都有什么:
里面一些很少用到的配置我都已经标注出来。可以看到里面添加了一些含有native方法的类、自定义View中的get、set方法、以及R类和带Keep注解的类的保护。
至此,打出的release包应该都是混淆过的,只不过除了默认的混淆规则外,我们没有为自己的apk添加自己的混淆规则,接下来我们看看如何给自己的apk添加混淆规则。
apk混淆规则的编写我大致认为分三个大的方面,Proguard的一些基础配置、Android项目的一些通用配置、根据自己需求定制的一些配置。
1.Proguard的一些基础配置:
-optimizationpasses 5 //代码混淆的压缩比例,值在0-7之间,Android一般推荐用5
-dontusemixedcaseclassnames //不使用大小写类名混淆(混淆后类名都为小写)
-dontskipnonpubliclibraryclasses //指定不去忽略非公共的库的类
-dontskipnonpubliclibraryclassmembers //指定不去忽略非公共的库的类的成员
-dontpreverify //不做预校验的操作
-verbose //混淆时显示详细日志
-dontoptimize //关闭优化
-printmapping proguardMapping.txt //生成原类名和混淆后的类名的映射文件
-dontwarn //忽略警告
-keepparameternames //保证方法参数不被混淆
-keepattributes *Annotation*,InnerClasses //不混淆Annotation和内部类
-keepattributes Signature //不混淆泛型
-keepattributes SourceFile,LineNumberTable //抛出异常时保留代码行号
当然这只是一些最基础的配置,大家可以根据自己的需要看后面的注释更改配置。
2.通用配置:
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
#移除log类中的d、v调用处
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
}
-keep public class com.android.vending.licensing.ILicensingService
-keep class android.support.** {*;}
#避免混淆所有native的方法
-keepclasseswithmembernames class * {
native <method