美文网首页Android专题
全面解析:Android开发中的Proguard混淆配置

全面解析:Android开发中的Proguard混淆配置

作者: 千夜零一 | 来源:发表于2020-10-19 12:14 被阅读0次

为什么要进行代码混淆?

  混淆在我们实际的Android开发中是必不可少的,如果不混淆, 发布出去,别人一反编译 就可以直接看你的源码了,那么在应用发布前,就需要对代码进行混淆处理,从而让我们代码即使被反编译,也难以阅读。一句话,使用混淆增强了应用软件的安全性!


认识Proguard工具

ProGuard is a Java class file shrinker, optimizer, obfuscator, and preverifier.

  从官方文档这段话中可以看出,Proguard可以对Java class文件执行shrink,optimize,obfuscate和preverify四项优化。这四项优化也代表了Proguard的四项功能。

  • 压缩(Shrink):侦测并移除代码中无用的类、字段、方法、和特性(Attribute)。
      具体解释:shrink功能的作用是移除代码中没有使用到的类,方法和成员变量,从而减少文件大小。这些没有使用到的类,方法和成员变量的产生主要有两种情况:
      1、自身代码由于功能需求的变更,或者代码重构,导致原本的代码不会再使用,或者不删除以备后续的使用,这些代码对程序的运行没有任何作用。
      2、项目中经常会包含一些开源代码或第三方SDK,而项目通常只会使用到开源代码或第三方SDK中的部分功能,那些没有用到的功能对应的代码同样是可以去掉的。
      Proguard的shrink功能就是用来执行这项操作的,它会自动分析jar包中各个类,方法之类的调用和依赖关系,对那些没有用到的类,方法和成员变量进行剔除。
  • 优化(OPtimize):对字节码进行优化,移除无用指令。
      optimize过程会在Java字节码层面上进行优化,剔除方法中一些冗余的调用。帮助文档中列出了一些当前Proguard支持的优化。
  • 混淆(Obfuscate):使用a、b、c、d这样简短而无意义的名称,对类、字段和方法进行重命名。
      obfuscator也就是Proguard最常被提到的代码混淆功能。由于Java代码编译之后的class文件中仍然包含了调试信息,源文件名,行号,类名,方法名,成员变量名,参数名,局部变量名等信息,通过反编译可以很容易的将这些信息还原出来。
      通过obfuscator,可以将jar包中不需要对外暴露的类名、方法名和变量名替换成一些简短的,对人来说没有意义的名字。
  • 预检(Preveirfy):在java平台上对处理后的代码进行预检。
      preverifier用来对Java class进行预验证。预验证主要是针对Java ME开发来说的,Android中没有预验证过程,所以不需要用到这项功能。

Android开发中的Proguard混淆

  在开发工具Android Studio中集成了ProGuard混淆的功能,在Android Sdk “tools\proguard\lib\proguard.jar“目录下,可以自行的查看、替换。它结合了gradle搭配使用。
  在app下的build.gradle中增加如下配置:

buildTypes {  
    debug {  
        versionNameSuffix ".debug"  
    }  

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

  这些代码会在app下生成与build.gradle同级的proguard-rules.pro文件,这还需要我们进行混淆配置。
  Tips:新生成的proguard-rules.pro都是没有添加混淆规则的,这需要我们手动的去编写、添加。


混淆配置

项目中的混淆分为两类:(具体代码为了不影响阅读,在后文贴)

  • 基本不变的混淆(系统推荐的不可混淆的文件配置)
  • 自己自行添加的配置(实体类、依赖的第三方框架、与wevview交互的js、一些反射的类)

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


总结

  Proguard经常被看做Android平台的代码混淆工具,这种看法是比较片面的。Proguard项目诞生于2002年,而Android 1.0是2008年才发布的,也就是说早在Android发布之前Proguard就已经存在很久了。Proguard不仅适用于Android项目,也适合对其他使用Java开发项目的优化。
  此外,Proguard也不仅仅是一个代码混淆工具,代码混淆只是Proguard四项功能中的其中一项。它之所以被认为是Android平台的代码混淆工具,是因为Google将其集成到了Android SDK和Android项目的编译过程中,成为Android开发默认的代码优化工具,从而被广大的Android开发者所熟悉。
  总而言之,Android开发者对代码混淆功能的需求比其他功能要迫切的多,Proguard代码混淆功能成为开发者必选的一项功能。

基本不变的混淆:

# 代码混淆压缩比,在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);
}

自己增添的混淆配置

# 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.** { *; }

#-------------------------------------------------------------------------

相关文章

网友评论

    本文标题:全面解析:Android开发中的Proguard混淆配置

    本文链接:https://www.haomeiwen.com/subject/llekmktx.html