Android开发中的混淆及配置

1 篇文章 0 订阅
1 篇文章 0 订阅

写在前面
混淆在我们实际的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调用也需要保证写的接口方法不混淆

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值