一、理论知识
ProGuard是一款免费的Java类文件压缩器、优化器和混淆器。它能发现并删除无用类、字段(field)、方法和属性值(attribute)。它也能优化字节码并删除无用的指令。最后,它使用简单无意义的名字来重命名你的类名、字段名和方法名。经过以上操作的jar文件会变得更小,并很难进行逆向工程。
二、基本使用
在Android应用程序也可以使用
ProGuard来进行混洗打包,大大的优化Apk包的大小。但是注意
ProGuard对文件路径的名名很有讲究,不支持括号,也不支持空格
。在混淆过后,可以在工程目录的
proguard中的
mapping.txt
看到混淆后的类名,方法名,变量名和
混淆前的类名,方法名,变量名。
在使用Eclipse或Ant打包应用程序时,都是使用Android工程目录的
project.properties
文件来指定配置。关于Android中如何使用ant打包请参考《
Android中使用Ant编译打包
》
在使用Eclipse新建一个工程,都会在工程目录下生产配置project.properties和proguard-project.tx。
文件如下所示:
例1
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir,user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.target=android-10
project.properties用于配置Android工程的一些属性,#号的话表示当前行是注释,这里的
proguard.config
就用于指定
ProGuard的
混淆配置文件,并对使用
release
方式打包应用程序时开启
代码混淆
功能。对于是否是
使用release方式打包,和
AndroidManifest.xml
中application的android:debuggable属性有很多关系。如果该值为
android:debuggable="
true
"
,那么最终就是
debug方式打包。最明智的方式就是在
AndroidManifest.xml并不显示的指定它,而是是打包工具在打包时来决定它最终的值。对于ant就是
ant
release
或
ant
debug。
而对于直接在Eclipse中使用
run
或
debgu
来打包的话就是debug,使用export的话就是
release.
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
这里的话指定了混淆的基本配置文件
proguard-android.txt,和
混淆的个性化配置文件
proguard-project.txt。这里
proguard-project.txt文件用于对前面的
基本的混淆配置文件
proguard-android.txt的配置进行override和添加。
混淆的基本配置文件
proguard-android.txt
如下:
文件1
# To enable ProGuard in your project, edit project.properties # to define the proguard.config property as described in that file. # # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in ${sdk.dir}/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the ProGuard # include property in project.properties. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} -optimizationpasses 5 -dontusemixedcaseclassnames -dontskipnonpubliclibraryclasses -dontpreverify -verbose -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* -dontwarn com.slidingmenu.** -keep class com.slidingmenu.** { *;} -dontwarn android.support.v4.** -keep class android.support.v4.** { *; } -keep public class * extends android.support.v4.** -keep public class * extends android.app.Fragment -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 com.android.vending.licensing.ILicensingService -keepclasseswithmembernames class * { native <methods>; } -keepclasseswithmembernames class * { public <init>(android.content.Context, android.util.AttributeSet); } -keepclasseswithmembernames class * { public <init>(android.content.Context, android.util.AttributeSet, int); } -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } -keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; } -keep class com.inno.libjingle.** { *; } -keep class com.inno.libupnp.** { *; }
三、混淆配置详解
另外以下是关于混淆配置文件的一些说明:
-
injars androidtest.jar【jar包所在地址】
-
outjars out【输出地址】
-
libraryjars 'D:\android-sdk-windows\platforms\android-9\android.jar' 【引用的库的jar,用于解析injars所指定的jar类】
-
optimizationpasses 5
-
dontusemixedcaseclassnames 【混淆时不会产生形形色色的类名 】
puzzle
-
dontskipnonpubliclibraryclasses 【指定不去忽略非公共的库类。 】
puzzle
-
dontpreverify 【不预校验】
-
verbose
-
optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 【优化】
puzzle
-
keep public class * extends android.app.Activity 【不进行混淆类名的类,保持其原类名和包名】
-
keep public abstract interface com.asqw.android.Listener{
public protected <methods>; 【所有public protected的方法名不进行混淆】
}
-
keep public class com.asqw.android{
public void Start(java.lang.String); 【对该方法不进行混淆】
}
-
keepclasseswithmembernames class * { 【对所有类的native方法名不进行混淆】
native <methods>;
}
-
keepclasseswithmembers class * { 【
对所有类的指定方法的方法名不进行混淆】
public <init>(android.content.Context, android.util.AttributeSet);
}
-
keepclassmembers class * extends android.app.Activity {【
对所有类的指定方法的方法名不进行混淆】
public void *(android.view.View);
}
-
keepclassmembers enum * {
【
对枚举类型enum的所有类的以下指定方法的方法名不进行混淆
】
public static **[] values();
public static ** valueOf(java.lang.String);
}
-
keep class * implements android.os.Parcelable {【对实现了
Parcelable接口的所有类的类名不进行混淆,对其成员变量为
Parcelable$Creator类型的成员变量的变量名不进行混淆
】
public static final android.os.Parcelable$Creator *;
}
-keepclasseswithmembers class org.jboss.netty.util.internal.LinkedTransferQueue {
【
对指定类的指定变量的变量名不进行混淆
】
volatile transient org.jboss.netty.util.internal.LinkedTransferQueue$Node head; volatile transient org.jboss.netty.util.internal.LinkedTransferQueue$Node tail; volatile transient int sweepVotes;}
-keep public class com.unionpay.** {*; }【对
com.unionpay
包下所有的类都不进行混淆,即不混淆类名,也不混淆方法名和变量名】