Android开发应该掌握的混淆器技巧

  

混淆器被人们熟知的是它的混淆功能,根据混淆器帮助文档的描述,混淆器可以对Java类文件进行萎缩,优化,混淆和preveirfy.obfuscate(混淆)只是其中之一。简要的介绍下这四个功能:

:检测和删除没有使用的类,字段,方法和特性

:分析和优化Java字节码

:使用简短的无意义的名称,对类,字段和方法进行重命名

:用来对Java类进行预验证(预验证主要是针对期刊开发来说的,安卓系统中没有预验证过程,默认是关闭)

补充说明:根据proguard-android-optimize.txt对优化的描述,在Android中使用该功能是有潜在风险的,并不能保证在所有版本的Dalvik虚拟机上正常运行,该选项默认是关闭的,如果开启,请做好全面的测试。在Android项目中,我们在相应的模块下的构建。gradle文件中会看到

 buildTypes {
  释放{
  minifyEnabled真实
  proguardFiles getDefaultProguardFile (“proguard-android.txt”)、“proguard-rules.pro”
  }
  }

其中minifyEnabled为真的是开启混淆器的功能,假是关闭。

Prouguard的工作流程如下图所示:

 Android开发应该掌握的混淆器技巧”> <br/> </p> <p class=可以看出,混淆器工作流程是对输入的罐子经过缩小→优化→混淆→preveirfy依次处理,图中库jar是输入罐子运行所依赖的包,比如Java运行时的rt.jar, Android运行时Android。罐子,这些罐子在上述处理过程中不会有任何改变,仅是作为输入罐的依赖。

大家可能会有一个疑问,混淆器是怎么知道哪些类,方法,成员变量等是无用的呢,这就要说到入口点(入口点),我们在配置文件(包括默认的proguard-android.txt)中写入的一系列小选项,都会作为切入点,混淆器把这些入口点作为搜索的入口,进行递归检索,以此来确定哪些部分未使用到。类似于热点虚拟机对可回收对象的判定,从GC根出发,进行可达性的判断,不可达的为可回收对象.Entry点非常重要,混淆器的压缩,优化,混淆功能是以入口点作为依据的(预检不需要以此为依据)。

在压缩过程中,混淆器从入口点出发,递归检索,删除那些没有使用到的类和类的成员,在接下来的优化过程中,那些非入口点的类和方法会被设置成私人的,静态或最后一个,没有使用到的参数会被移除,有些方法可能会被标记为内联的,在混淆过程中,会对非入口点的类和类的成员进行重命的名,也就是用其它无意义的名称代替。我们在配置文件中用小保留的部分属于入口点,所以不会被重命名。

说起重命名,为什么需要保留一些类和类的成员(方法和变量)不被重命名呢?原因是混淆器对类文件经过一系列处理后,能保证功能上和原来是一样的,但有些情况它却不能良好的处理,比如我们代码中有些功能依赖于它们原来的名字,如反射功能,本地调用(函数签名)等,如果换成其它名字,会出现找不到,不对应的情况,可能引起程序崩溃,或者我们的对外提供了一些功能,必须保持原来的名字,才能保证其它依赖这些功能的模块能正确的运行等。

这就是我们为什么要配置小选项的原因之一,还有一个原因是我们要用小告诉混淆器程序的入口(带有小的选项都会作)为切入点,以此来确定哪些是未被使用的类和类的成员,方法等,并删除它们,因此,我们要针对我们的项目配置对应的选项。当然混淆器不仅提供了小选项,还有一些其它配置选项,比如-dontoptimize对输入的Java类文件不进行优化处理,- verbose生成混淆后的映射文件等。下面介绍一下应用中混淆器文件的常用配置和项目中可能会用到的指令。更多详细的用法,可以参考混淆器帮助文档。

第1条是可以作为Android应用的配置模板的(默认的proguard-android.txt文件里的配置没有列举出来),基本所有的应用都会用的到。

 #代码混淆压缩比,在0 ~ 7之间,默认为5,一般不做修改-optimizationpasses 5 #把混淆类中的方法名也混淆了-useuniqueclassmembernames #优化时允许访问并修改有修饰符的类和类的成员-allowaccessmodification #避免混淆内部类、泛型,匿名类-keepattributes InnerClasses,签名,EnclosingMethod #抛出异常时保留代码行号-keepattributes源文件,LineNumberTable #重命名抛出异常时的文件名称为“源文件”-renamesourcefileattribute源文件#保持所有实现可序列化的接口的类成员-keepclassmembers Java类*实现。可序列化的{静态最终serialVersionUID长;私有静态最终io。ObjectStreamField [] serialPersistentFields;私人空间writeObject (java.io.ObjectOutputStream);私人空间readObject (java.io.ObjectInputStream);
  爪哇. 朗。对象writeReplace ();
  爪哇. 朗。对象readResolve ();
  }#保留我们使用的四大组件,自定义等的应用等这些类不被混淆#因为这些子类都有可能被外部调用小公共类* android.app延伸。活动小公共类* android.app延伸。立小公共类* android.app延伸。服务小公共类* android.content延伸。BroadcastReceiver小公共类* android.content延伸。ContentProvider小公共类* android.app.backup延伸。BackupAgentHelper小公共类* android.preference延伸。偏好#保留支持下的所有类及其内部类
  android.support小类。* *{*;}#保留继承的支持类小公共类* android.support.v4。* *
  小公共类* android.support.v7。* *
  小公共类* android.support.annotation。* *
  #保留我们自定义控件(继承自视图)不被混淆
  小公共类*扩展android.view.View {
  * * * * ();
  空集* (* * *);公共& lt; init> (android.content.Context);公共& lt; init> (android.content。背景下,android.util.AttributeSet);公共& lt; init> (android.content。上下文,android.util。AttributeSet, int);
  }#片段不需要在AndroidManifest。xml中注册,需要额外保护下小公共类* android.app延伸。片段#保持测试相关的代码
  -dontnote junit.framework。* *
  -dontnote junit.runner。* *
  -dontwarn android.test。* *
  -dontwarn android.support.test。* *
  -dontwarn org.junit。* * 

Android开发应该掌握的混淆器技巧