1、混淆的好处
android studio 使用ProGuard来进行混淆,ProGuard是一个压缩、优化和混淆java字节码文件的工具,可以删除无用的类,字段,方法和属性,还可以删除无用额注释,最大限度的优化字节码文件,规避64K方法数的问题,并且还可以使用剪短而且无意义的名字来重命名已经存在的类、字段、方法和属性,增加逆向工程的难度。混淆可以减少APK文件的大小。
2、混淆包含:压缩,优化,混淆,预校验四个操作。
压缩Shringking : 检测和删除无用的类,方法,字段和属性
优化Optimize : 优化字节码文件,删除无用指令
混淆Obfuscation :使用无意义的名字来对类,字段,方法和属性进行重命名
预校验Preverification:对处理后的代码进行校验
proguard原理介绍可以看看proguard的官网
proguard流程:
3、build文件打开混淆
buildTypes {
release {
minifyEnabled true //打开混淆
shrinkResources true //打开资源压缩
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//设置混淆文件的路径,第一部分为系统已经预先设置的混淆文件,第二部分是我们自己的混淆文件
}
}
当我们新建module的时候,是默认已经关闭混淆了的,要打开混淆只要设置minifyEnabled = true就可以
proguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-rules.pro’
proguard-android.txt为系统已经预先设置的混淆文件,proguard-rules.pro是我们自己的混淆文件
基本的混淆设置:
指定压缩级别,0-7之间,默认为5
-optimizationpasses 5
不使用大小写混合类名,注意,windows用户必须为ProGuard指定该选项,因为windows对文件的大小写是不敏感的,也就是比如a.java和A.java会认为是同一个文件。如果不这样做并且你的项目中有超过26个类的话,那么ProGuard就会默认混用大小写文件名,导致class文件相互覆盖。
-dontusemixedcaseclassnames
不跳过非公共的库类
-dontskipnonpubliclibraryclasses
不跳过非公共的库类的成员
-dontskipnonpubliclibraryclassmembers
指定不执行预检,预校验作用在Java平台,android平台不需要,所以去掉预校验可以加快混淆速度
-dontpreverify
把所有信息都输出,而不仅仅是输出出错信息
-verbose
输出类名->混淆后类名的映射关系
-printmapping proguardMapping.txt
混淆时采用的算法
-optimizations !code/simplification/cast,!field/,!class/merging/
不混淆Annotation
-keepattributes Annotation,InnerClasses
不混淆泛型
-keepattributes Signature
保留行号
-keepattributes SourceFile,LineNumberTable
以下情况不能被混淆:
1.
反射中使用的元素,需要保证类名,方法名,属性名不变,否则混淆后会反射不了
最好不要混淆bean对象
四大组件不建议混淆,自定义的Application不能被混淆,混淆以后类名会变,,而混淆后的类名没有在manifest中注册,所以不符合四大组件的注册机制
外部程序可能使用组件的字符串类名,如果类名混淆,可能导致出现异常
-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 public class com.android.vending.licensing.ILicensingService
2.自定义view和自定义控件不能被混淆
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
3.枚举类的values和valuesOf方法不能被混淆,因为这两个方法是静态添加到代码中运行,也会被反射使用,所以不能混淆这两个方法
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
4.R类下面的资源不能被混淆
-keep class **.R$* {*;}
5.JNI调用java方法不能被混淆,需要通过类名和方法名构成的地址形成
6.webview中的js方法不能混淆
-keepclassmembers class fqcn.of.javascript.interface.for.webview {
public *;
}
-keepclassmembers class * extends android.webkit.webViewClient {
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.webViewClient {
public void *(android.webkit.webView, jav.lang.String);
}
7.Java调用Native方法,Native方法是C/C++编写的,方法是无法一同混淆的
-keepclasseswithmembernames class * {
native <methods>;
}
8. 第三方库建议使用其自身的混淆规则
9. Parcelable的子类和Creator的静态成员变量不能混淆,否则序列化会出异常
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
10.保留Serializable序列化的类不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
11.JS调用原生的方法不能被混淆
-keepattributes *JavascriptInterface*
以上是一些基本的不能被混淆的情况。
是不是有一种头晕目眩的感觉呢?其实混淆不复杂,我们只需要记住一点:
混淆改变了Java路径名,需要保持路径名不变的不可以被混淆
只要牢记这个原则来添加自己不需要被混淆的类就可以啦。
另外support-annotation中提供了@Keep注解,可以保持类不被混淆,哪里不想被混淆就"keep"那里
要使用@Keep需要在proguard文件里加入:
-dontskipnonpubliclibraryclassmembers
-printconfiguration
-keep,allowobfuscation @interface android.support.annotation.Keep
-keep @android.support.annotation.Keep class *
-keepclassmembers class * {
@android.support.annotation.Keep *;
}
那么是否有更深层次的混淆呢?
ProGuard只能混淆java文件,实际上我们还可以混淆资源文件的文件路径,其实质也是资源名的混淆。
这里要提到AndResGuard混淆插件
github地址:
AndResGuard/README.zh-cn.md at master · shwenzhang/AndResGuard · GitHub
https://github.com/shwenzhang/AndResGuard/blob/master/README.zh-cn.md
它会重新修改apk的resource.arsc文件,不依赖源码和编译过程,可以使用zip压缩。
具体的使用,大家可以参考官方git。