Android开发中的混淆及配置

来源:互联网 发布:mysql 最近10条记录 编辑:程序博客网 时间:2024/06/05 00:16

写在前面
混淆在我们实际的Android开发中是必不可少的,如果不混淆, 发布出去,别人一反编译 就可以直接看你的源码了,那么在应用发布前,就需要对代码进行混淆处理,从而让我们代码即使被反编译,也难以阅读。
ProGuard作用
proguard拥有以下四个功能。
压缩(Shrink):侦测并移除代码中无用的类、字段、方法、和特性(Attribute)。
优化(OPtimize):对字节码进行优化,移除无用指令。
混淆(Obfuscate):使用a、b、c、d这样简短而无意义的名称,对类、字段和方法进行重命名。
预检(Preveirfy): 在java平台上对处理后的代码进行预检。
Android开发中的混淆
这里说明下Android Studio中的使用情况,在开发工具Android Studio中集成了ProGuard混淆的功能,在Android Sdk “tools\proguard\lib\proguard.jar“目录下,可以自行的查看、替换。它结合了gradle搭配使用。
在gradle中的使用:

buildTypes {      debug {          versionNameSuffix ".debug"      }      release {          debuggable false          minifyEnabled true  //将minifyEnabled 属性设置为true        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'          signingConfig signingConfigs.release      }  } 

proguard-rules.pro在项目的module结构中:


混淆文件的位置
新生成的proguard-rules.pro都是没有添加混淆规则的,这需要我们手动的去编写、添加。

混淆配置
在项目中的混淆配置一般可分为两大类:
一、基本不变的混淆(系统推荐的不可混淆的文件配置)
二、自己自行添加的配置(实体类、依赖的第三方框架、与wevview交互的js、一些反射的类)
基本不变的混淆

# 代码混淆压缩比,在0~7之间,默认为5,一般不下需要修改-optimizationpasses 5# 混淆时不使用大小写混合,混淆后的类名为小写 windows下的同学还是加入这个选项吧(windows大小写不敏感)-dontusemixedcaseclassnames# 指定不去忽略非公共的库的类# 默认跳过,有些情况下编写的代码与类库中的类在同一个包下,并且持有包中内容的引用,此时就需要加入此条声明-dontskipnonpubliclibraryclasses# 指定不去忽略非公共的库的类的成员-dontskipnonpubliclibraryclassmembers# 不做预检验,preverify是proguard的四个步骤之一 Android不需要preverify,去掉这一步可以加快混淆速度-dontpreverify# 混淆后就会生成映射文件 包含有类名->混淆后类名的映射关系 然后使用printmapping指定映射文件的名称-verbose-printmapping priguardMapping.txt# 保护代码中的Annotation不被混淆 这在JSON实体映射时非常重要,比如fastJson-keepattributes *Annotation*# 避免混淆泛型 这在JSON实体映射时非常重要,比如fastJson-keepattributes Signature# 抛出异常时保留代码行号-keepattributes SourceFile,LineNumberTable# 指定混淆时采用的算法,后面的参数是一个过滤器 这个过滤器是谷歌推荐的算法,一般不改变-optimizations !code/simplification/artithmetic,!field/*,!class/merging/*--------------------------------------------------------------------------# 保留了继承自Activity、Application这些类的子类 不被混淆-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# 保留所有的本地native方法不被混淆-keepclasseswithmembernames class * {    native <methods>;}# 保留Activity中的方法参数是view的方法,从而我们在layout里面编写onClick就不会影响-keepclassmembers class * extends android.app.Activity {    public void * (android.view.View);}# 枚举类不能被混淆-keepclassmembers enum * {    public static **[] values();    public static ** valueOf(java.lang.String);}# 保留自定义控件(继承自View) 并且 get、set方法 不被混淆 -keep public class * extends android.view.View {    public <init>(android.content.Context);    public <init>(android.content.Context, android.util.AttributeSet);    public <init>(android.content.Context, android.util.AttributeSet, int);    public void set*(***);    *** get* ();}-keepclasseswithmembers class * {    public <init>(android.content.Context, android.util.AttributeSet);    public <init>(android.content.Context, android.util.AttributeSet, int);}# 保留Parcelable序列化的类不能被混淆-keep class * implements android.os.Parcelable{    public static final android.os.Parcelable$Creator *;}# 保留Serializable 序列化的类不被混淆-keepclassmembers class * implements java.io.Serializable {   static final long serialVersionUID;   private static final java.io.ObjectStreamField[] serialPersistentFields;   !static !transient <fields>;   private void writeObject(java.io.ObjectOutputStream);   private void readObject(java.io.ObjectInputStream);   java.lang.Object writeReplace();   java.lang.Object readResolve();}# 对R文件下的所有类及其方法,都不能被混淆-keepclassmembers class **.R$* {    *;}# 对于带有回调函数onXXEvent的,不能混淆-keepclassmembers class * {    void *(**On*Event);}# 如果有引用android-support-v4.jar包,可以添加下面这行-keep public class fragment所在文件的路径.** {*;}# 避免NoClassDefFoundError异常 同上一起使用-libraryjars ./libs/android-support-v4.jar-dontwarn android.support.v4.** -dontwarn **CompatHoneycomb-dontwarn **CompatHoneycombMR2-dontwarn **CompatCreatorHoneycombMR2-keep interface android.support.v4.app.** { *; }-keep class android.support.v4.** { *; }-keep public class * extends android.support.v4.**-keep public class * extends android.app.Fragment# webview的一些文件不混淆-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);}

自己自行添加的配置(可选)
实体类不被混淆
在与服务器端交互,将json数据映射到本地的实体类,不被混淆,建议将所有的实体类放在统一路径下,方便管理。

# com.example.entity是存放实体类的路径-keep class com.xx.entity.** {    //全部忽略    *;}

第三方依赖
这部分要根据自己项目中依赖的框架而定,常见的配置如下:

#---------------------------------常见第三方配置(可选)-------------------------------#eventBus-keepattributes *Annotation*-keepclassmembers class ** {    @org.greenrobot.eventbus.Subscribe <methods>;}-keep enum org.greenrobot.eventbus.ThreadMode { *; }-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {    <init>(java.lang.Throwable);}#glide-keep public class * implements com.bumptech.glide.module.GlideModule-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {  **[] $VALUES;  public *;}#butterknife-keep class butterknife.** { *; }-dontwarn butterknife.internal.**-keep class **$$ViewBinder { *; }-keepclasseswithmembernames class * {    @butterknife.* <fields>;}-keepclasseswithmembernames class * {    @butterknife.* <methods>;}#gson-keepattributes Signature-keepattributes *Annotation*-keep class sun.misc.Unsafe { *; }-keep class com.google.gson.stream.** { *; }# Application classes that will be serialized/deserialized over Gson 下面替换成自己的实体类-keep class com.example.bean.** { *; }#retrofit2-dontwarn retrofit2.**-keep class retrofit2.** { *; }-keepattributes Signature-keepattributes Exceptions#rxjava/rxAndroid-dontwarn sun.misc.**-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {   long producerIndex;   long consumerIndex;}-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {    rx.internal.util.atomic.LinkedQueueNode producerNode;}-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {    rx.internal.util.atomic.LinkedQueueNode consumerNode;}#okhttp3-dontwarn com.squareup.okhttp3.**-keep class com.squareup.okhttp3.** { *;}-dontwarn okio.**#友盟统计-keepclassmembers class * {   public <init> (org.json.JSONObject);}-keep public class [您的应用包名].R$*{  public static final int *;}-keepclassmembers enum * {  public static **[] values(); public static ** valueOf(java.lang.String);}#极光推送-dontoptimize-dontpreverify-dontwarn cn.jpush.**-keep class cn.jpush.** { *; }-keep class * extends cn.jpush.android.helpers.JPushMessageReceiver { *; }-dontwarn cn.jiguang.**-keep class cn.jiguang.** { *; }#-------------------------------------------------------------------------

注:以上配置都是常见的第三方混淆,如有不当可以自行google,以最新的官网文档为准。
内部类、js交互、反射
一些内部类不希望被混淆,与js交互的不被混淆。

# 指定反射类所在的包 不被混淆-keep class 你的类所在的包.** { *; }# 你的类所在的包.父类$子类 { <methods>; }-keepclasseswithmembers class com.example.ui.MainActivity$JSInterface {       <methods>; }

混淆配置注意事项:
1.反射用到的类不混淆
2.JNI方法不混淆
3.AndroidMainfest中的类不混淆,四大组件和Application的子类和Framework层下所有的类默认不会进行混淆
4.Parcelable的子类和Creator静态成员变量不混淆,否则会产生android.os.BadParcelableException异常
5.使用GSON、fastjson等框架时,所写的JSON对象类不混淆,否则无法将JSON解析成对应的对象
6.使用第三方开源库或者引用其他第三方的SDK包时,需要在混淆文件中加入对应的混淆规则
7.有用到WebView的JS调用也需要保证写的接口方法不混淆