ProGuard简介

       ProGuard是一个SourceForge上非常知名的开源项目。官网网址是:http://proguard.sourceforge.net/。

       Java的字节码一般是非常容易反编译的。为了很好的保护Java源代码,我们往往会对编译好的class文件进行混淆处理。ProGuard的主要作用就是混淆。当然它还能对字节码进行缩减体积、优化等,但那些对于我们来说都算是次要的功能。


       引用ProGuard官方的一段话来介绍就是:

       ProGuard is a free Java class file shrinker, optimizer, obfuscator, and preverifier. It detects and removes unused classes, fields, methods, and attributes. It optimizes bytecode and removes unused instructions. It renames the remaining classes, fields, and methods using short meaningless names. Finally, it preverifies the processed code for Java 6 or for Java Micro Edition.


Android Eclipse开发环境与ProGuard

       在Android 2.3以前,混淆Android代码只能手动添加proguard来实现代码混淆,非常不方便。而2.3以后,Google已经将这个工具加入到了SDK的工具集里。具体路径:SDK\tools\proguard。当创建一个新的Android工程时,在工程目录的根路径下,会出现一个proguard的配置文件proguard.cfg。也就是说,我们可以通过简单的配置,在我们的elipse工程中直接使用ProGuard混淆Android工程。 集成的ADT现在创建一个新的Android工程时,在工程目录的根路径下、会有一个proguard-project.txt。其实这个文件跟proguard.cfg是一样的。混淆打包的一些配置写在这个文件里就行了。

       搜了下Proguard混淆打包相关信息,搜来搜去都说的都大同小异,只要懂得了基本的一些使用方法,哪些混淆,哪些不混淆,最常见的就是过滤掉一些android需要注册的一些组件不混淆,第三方包也不需要混淆,因为有的第三方包已经混淆过了,大致的按照自己需要混淆的需求,写个基本配置就行了。在这里我做了个基本的综合、proguard配置如下:


[plain] view plain copy 在CODE上查看代码片派生到我的代码片

  1. -optimizationpasses 7  

  2. -dontusemixedcaseclassnames  

  3. -dontskipnonpubliclibraryclasses  

  4. -dontpreverify  

  5. -verbose  

  6. -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*  

  7.   

  8.   

  9. -keep public class * extends android.app.Activity  

  10. -keep public class * extends android.app.Application  

  11. -keep public class * extends android.app.Service  

  12. -keep public class * extends android.content.BroadcastReceiver  

  13. -keep public class * extends android.content.ContentProvider  

  14. -keep public class * extends android.app.backup.BackupAgentHelper  

  15. -keep public class * extends android.preference.Preference  

  16. -keep public class com.android.vending.licensing.ILicensingService  

  17.   

  18.   

  19. -keepclasseswithmembernames class * {  

  20.     native <methods>;  

  21. }  

  22.   

  23. -keepclasseswithmembers class * {  

  24.     public <init>(android.content.Context, android.util.AttributeSet);  

  25. }  

  26.   

  27. -keepclasseswithmembers class * {  

  28.     public <init>(android.content.Context, android.util.AttributeSet, int);  

  29. }  

  30.   

  31. -keepclassmembers class * extends android.app.Activity {   

  32.     public void *(android.view.View);  

  33. }  

  34.   

  35. -keep public class * extends android.view.View {  

  36.     public <init>(android.content.Context);  

  37.     public <init>(android.content.Context, android.util.AttributeSet);  

  38.     public <init>(android.content.Context, android.util.AttributeSet, int);  

  39.     public void set*(...);  

  40. }  

  41.   

  42. -keepclassmembers enum * {  

  43.     public static **[] values();  

  44.     public static ** valueOf(java.lang.String);  

  45. }  

  46.   

  47. -keep class * implements android.os.Parcelable {  

  48.     public static final android.os.Parcelable$Creator *;  

  49. }  

  50.   

  51. -keepnames class * implements java.io.Serializable  

  52.   

  53. -keepclassmembers class * implements java.io.Serializable {  

  54.     static final long serialVersionUID;  

  55.     private static final java.io.ObjectStreamField[] serialPersistentFields;  

  56.     !static !transient <fields>;  

  57.     private void writeObject(java.io.ObjectOutputStream);  

  58.     private void readObject(java.io.ObjectInputStream);  

  59.     java.lang.Object writeReplace();  

  60.     java.lang.Object readResolve();  

  61. }  

  62.   

  63. -keepattributes *Annotation*  

  64. -keepattributes Exceptions,InnerClasses,Signature  

  65. -keepattributes SourceFile,LineNumberTable  

  66.   

  67. -keep class **.R$* { *; }  

  68. -libraryjars  libs/android-support-v4.jar  

  69. -dontwarn android.support.v4.**      

  70. -keep class android.support.v4.** { *; }    

  71. -keep interface android.support.v4.** { *; }  

  72. -keep public class * extends android.support.v4.**   

  73. -keep public class * extends android.app.Fragment  



       它主要保留了继承自Activity、Application、Service、BroadcastReceiver、ContentProvider、BackupAgentHelper、Preference和ILicensingService的子类。因为这些子类,都是可能被外部调用的。

       另外,它还保留了含有native方法的类、构造函数从xml构造的类(一般为View的子类)、枚举类型中的values和valueOf静态方法、继承Parcelable的跨进程数据类和实现Serializable对象序列化。

       若有其他第三方包,可依依添加不混淆配置就行了。可根据要求,去个性配置proguard混淆就行了。


最后记住把根目录路径下的project.properties文件:


[plain] view plain copy 在CODE上查看代码片派生到我的代码片

  1. # This file is automatically generated by Android Tools.  

  2. # Do not modify this file -- YOUR CHANGES WILL BE ERASED!  

  3. #  

  4. # This file must be checked in Version Control Systems.  

  5. #  

  6. # To customize properties used by the Ant build system edit  

  7. # "ant.properties", and override values to adapt the script to your  

  8. # project structure.  

  9. #  

  10. # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):  

  11. #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt  

  12.   

  13. # Project target.  

  14. target=android-17  


proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

红色的那句注释(去掉“#”号)的打开放在最下面,就可以签名混淆打包apk去了。





自Android 2.3 SDK发布后,Google便在Android SDK Tools里加入了proguard,proguard是一个可以对.java文件进行一定程度上的代码混淆,使用proguard是一件极方便工作,在你项目中没有其他外部Jar包的情况下,在“project.properties”文件里,添加一行:

  1. proguard.config=proguard.cfg

复制代码

     代码即可,然后通过Android Tools(右击项目名)里导出APK即可,如果项目所使用的的SDK版本低于2.3,只需要进行%android_dir%/tools/lib目录,复制proguard.cfg文件到项目的根目录下导出APK即可。
      这是一般情况,即无第三方Jar包,如果存在第三方Jar包,那么打开proguard.cfg文件进行编辑,在其中加入以下代码:

  1. -libraryjars %lib_jar_path%

复制代码

     有几个Jar包,便添加几次,如在项目的libs目录下有a.jar,b.jar,c.jar三个Jar包:

  1. -libraryjars libs/a.jar

  2. -libraryjars libs/b.jar

  3. -libraryjars libs/c.jar

复制代码

     如此,通过android tools导出APK即可。
      此外,还有些特殊情况,会令导出发生异常,视具体异常情况而定,修改proguard.cfg文件。
      比如出现了以下异常:

  1. Warning: com.google.android.maps.MapView: can't find referenced class com.android.mkstubs.stubber.MethodStubber

  2. Warning: com.google.android.maps.MapView$1: can't find referenced class com.android.mkstubs.stubber.MethodStubber

复制代码

即:

  1. Warning: %class_full_name%: can't find referenced class %class_full_name%

复制代码

     这种异常情况,需要在proguard.cfg文件中,添加以下代码:

  1. -dontwarn %class_full_name%

复制代码

     即可,便以上面例子而言,应当如下:

  1. -dontwarn com.google.android.maps.*

复制代码

     等等,此类情况修改proguard.cfg文件即可,还有种特殊情况,需要对引入的Jar包进行修改,如下:

  1. Warning: library class android.content.res.XmlResourceParser extends or implements program class org.xmlpull.v1.XmlPullParser

  2. Warning: library class android.view.LayoutInflater depends on program class org.xmlpull.v1.XmlPullParser

复制代码

     这是因为引用的Jar包中含有xmlpull类库,Android系统的类库中已经包含了xmlpull,这样混淆出现了冲突,解决办法是把它里面已存在的和系统库冲突的类去掉,就可以了,产生冲突的类可见控制台输出。
      另外对不想混淆的类/方法/变量,可以使用-keep指定,具体参考proguard.cfg文件写法。