Proguard簡介
介紹
ProGuard is a Java class file shrinker, optimizer, obfuscator, and preverifier.

- shrink:去除無用的類和成員
- optimize:進一步優化,方法内聯,去除無用方法參數,非入口方法變成私有,靜态的,final
- obfuscate:非入口點的方法和類進行重命名
- preverify:android是不需要這一步的,隻針對标準的.jar
我是官方文檔,戳我!
jar轉換關系
inputjars 到 outputjars的關系 是多對多
多對一
-injars in.jar
-injars /usr/local/java/scala-./lib/scala-library.jar
-outjars out.jar
多對多
-injars proguardgui.jar
-outjars proguardgui_out.jar
-injars proguard.jar
-outjars proguard_out.jar
-libraryjars <java.home>/lib/rt.jar
-applymapping proguard.map
-keep public class proguard.gui.ProGuardGUI {
public static void main(java.lang.String[]);
}
一對多
-injars in.jar
-outjars code_out.jar(**.class)
-outjars resources_out.jar
簡單的關鍵字說明
-keep [,modifier,…] class_specification
儲存類和類成員 ,先查找指定的類,然後儲存指定的類中的相關成員,同時做為入口點
-keepclassmembers [,modifier,…] class_specification
儲存類成員
-keepclasseswithmembers [,modifier,…] class_specification
儲存指定的類成員存在的類和類成員,先查找包含指定成員的類,然後比對指定的類
**-keepnames class_specification
縮寫 -keep,allowshrinking class_specification**
儲存在瘦身階段沒有被移除的類和類成員的名字,僅僅用來obfuscate階段
**-keepclassmembernames class_specification
縮寫 -keepclassmembers,allowshrinking class_specification**
儲存在瘦身階段沒有被移除的類成員的名字,僅僅用來obfuscate階段
**-keepclasseswithmembernames class_specification
縮寫 -keepclasseswithmembers,allowshrinking class_specification**
儲存在瘦身階段沒有被移除的,并且指定的類成員出現的類和類成員的名字,僅僅用來obfuscate階段
-printseeds [filename]
列出所有比對-keep的類和類成員,在處理過程進行标準的輸出,或者輸出在檔案中
-printmapping [filename]
将混淆後的映射關系輸出到指定的檔案.
-dontwan [class_filter]
不處理無法解析引用以及一些其它重要的問題
基本的比對規則
[@annotationtype] [[!]public|final|abstract|@ ...] [!]interface|class|enum classname
[extends|implements [@annotationtype] classname]
[{
[@annotationtype] [[!]public|private|protected|static|volatile|transient ...] <fields> | (fieldtype fieldname);
[@annotationtype] [[!]public|private|protected|static|synchronized|native|abstract|strictfp ...] <methods> | <init>(argumenttype,...) | classname(argumenttype,...) | (returntype methodname(argumenttype,...));
[@annotationtype] [[!]public|private|protected|static ... ] *;
...
}]
基本符号說明:
字元 | 解釋 | 例子 |
---|---|---|
@ | 注釋 | @Deprecated public class * // 可以比對所有被@Deprecated修飾的類 |
! | 非 | |
[] | 可選項 | |
<> | 特定的含義,下面詳細說明 | |
| | 或者 | |
() | 組合 | (fieldtype filedname)組合在一起進行限定 |
; | 域或者方法後面需要加上 | |
* | 通配符 |
<>的說明:
<> | 說明 |
---|---|
< init > | 比對任意的構造函數 |
< fields > | 比對任意的域 |
< methods > | 比對任意的方法 |
classname的說明:
classname是必選項,是帶上包名的完整類名.如果有内部類可以用 符号進行組合.如android.view.View OnClickListener同時可以使用通配符:
符号 | 說明 |
---|---|
? | 用來比對除包分隔符.之外的其他任意單個字元 |
* | 用來比對任意多個字元(包括0個),比對不能跨越包分隔符.。 |
** | 用來比對任意多個字元(包括0個),和*不同的是,**比對可以跨越包分隔符。 |
filedtype 和 filename一起使用:
filedtype的通配符:
符号 | 說明 |
---|---|
% | 用來比對任意Java基本資料類型(包括byte,short,int,long,float,double,char和boolean,不包括void) |
\? | 用來比對成員變量類型中除包分隔符.之外的任意單個字元 |
* | 用來比對成員變量類型中除包分隔符.之外的任意多個字元(包括0個) |
** | 用來比對成員變量類型中任意多個字元(包括0個),包括包分隔符. |
*** | 用來比對任意類型,包括基本資料類型和數組 |
filename的通配符:
符号 | 說明 |
---|---|
? | 用來比對成員變量名中任意單個字元 |
* | 用來比對成員變量名中任意多個字元(包括0個) |
優化參數說明
官方優化選項說明
語句(部分) | 說明 |
---|---|
class/marking/final | 盡可能的使類成為final類型 |
class/unboxing/enum | 盡可能的簡化枚舉類型為整數常來功能 |
class/merging/vertical | 盡可能的在類層級垂直方向進行合并 |
class/merging/horizontal (⇒ code/removal/advanced) | 盡可能的在類層級水準方向進行合并 |
field/removal/writeonly | 移除隻讀的域 |
field/marking/private (⇒ code/simplification/advanced) | 盡可能的使域權限為私有 |
field/propagation/value | 通過方法傳遞域值 |
method/marking/private (⇒ code/removal/advanced) | 盡可能的使方法為私有 |
method/marking/static | 盡可能的使方法為私有 |
method/marking/final (⇒ code/removal/advanced) | 盡可能使方法為final |
method/removal/parameter(⇒ code/simplification/advanced) | 移除無用的方法參數 |
混淆保留的分類
保留原則:
1.外部可能需要使用的
2.反射相關
- 保留序列化
//僅僅在記憶體使用
-keepclassmembers class * implements java.io.Serializable {
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
//需要存儲的序列化,需要額外加上
-keepnames class * implements java.io.Serializable
//需要相容老的資料
-keepnames class * implements java.io.Serializable
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
- 保留反射
- 保留枚舉
-keepclassmembers,allowoptimization enum * {
public static **[] values(); public static ** valueOf(java.lang.String);
}
- 保留bean
keep public class mypackage.MyBean {
public void setMyProperty(int);
public int getMyProperty();
}
-keep public class mypackage.MyBeanEditor
#更加通用的方式
-keep class mybeans.** {
void set*(***);
void set*(int, ***);
boolean is*();
boolean is*(int);
*** get*();
*** get*(int);
}
- 保留native
-keepclasseswithmembernames,includedescriptorclasses class * {
native <methods>;
}
- 保留回調
-keep class mypackage.MyCallbackClass {
void myCallbackMethod(java.lang.String);
}
- 保留資料庫驅動
8. 保留UI
#java的UI
-keep class * extends javax.swing.plaf.ComponentUI {
public static javax.swing.plaf.ComponentUI createUI(javax.swing.JComponent);
}
#android的UI
-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*(...);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
9. 保留RMI代碼
對于android來說就AIDL
proguard的使用
Proguard被內建在android sdk 中,其目錄是\
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true
proguardFiles getDefaultProguardFile(‘proguard-android.txt‘), ‘proguard-rules.pro‘
}
}
- 通過makefile編譯, 混淆
android.mk檔案中加入
ifeq ("$(isProguard)","false") //isProguard是上層腳本定義的一個變量
LOCAL_PROGUARD_ENABLED := disabled
else
LOCAL_PROGUARD_ENABLED := custom
endif
proguard_options_file := $(LOCAL_PATH)/src/app/proguard-rules.pro
LOCAL_PROGUARD_FLAGS := $(addprefix -include ,$(proguard_options_file)) $(LOCAL_PROGUARD_FLAGS)
android 官方混淆模闆
#
# This ProGuard configuration file illustrates how to process Android
# applications.
# Usage:
# java -jar proguard.jar @android.pro
#
# If you're using the Android SDK (version 2.3 or higher), the android tool
# already creates a file like this in your project, called proguard.cfg.
# It should contain the settings of this file, minus the input and output paths
# (-injars, -outjars, -libraryjars, -printmapping, and -printseeds).
# The generated Ant build file automatically sets these paths.
# Specify the input jars, output jars, and library jars.
# Note that ProGuard works with Java bytecode (.class),
# before the dex compiler converts it into Dalvik code (.dex).
-injars bin/classes
-injars libs
-outjars bin/classes-processed.jar
-libraryjars /usr/local/android-sdk/platforms/android-/android.jar
#-libraryjars /usr/local/android-sdk/add-ons/google_apis-7_r01/libs/maps.jar
# ...
# Save the obfuscation mapping to a file, so you can de-obfuscate any stack
# traces later on.
-printmapping bin/classes-processed.map
# You can print out the seeds that are matching the keep options below.
#-printseeds bin/classes-processed.seeds
# Preverification is irrelevant for the dex compiler and the Dalvik VM.
-dontpreverify
# Reduce the size of the output some more.
-repackageclasses ''
-allowaccessmodification
# Switch off some optimizations that trip older versions of the Dalvik VM.
-optimizations !code/simplification/arithmetic
# Keep a fixed source file attribute and all line number tables to get line
# numbers in the stack traces.
# You can comment this out if you're not interested in stack traces.
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
# RemoteViews might need annotations.
-keepattributes *Annotation*
# Preserve all fundamental application classes.
-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
# Preserve all View implementations, their special context constructors, and
# their setters.
-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*(...);
}
# Preserve all classes that have special context constructors, and the
# constructors themselves.
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
# Preserve all classes that have special context constructors, and the
# constructors themselves.
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
# Preserve the special fields of all Parcelable implementations.
-keepclassmembers class * implements android.os.Parcelable {
static android.os.Parcelable$Creator CREATOR;
}
# Preserve static fields of inner classes of R classes that might be accessed
# through introspection.
-keepclassmembers class **.R$* {
public static <fields>;
}
# Preserve the required interface from the License Verification Library
# (but don't nag the developer if the library is not used at all).
-keep public interface com.android.vending.licensing.ILicensingService
-dontnote com.android.vending.licensing.ILicensingService
# The Android Compatibility library references some classes that may not be
# present in all versions of the API, but we know that's ok.
-dontwarn android.support.**
# Preserve all native method names and the names of their classes.
-keepclasseswithmembernames class * {
native <methods>;
}
# Preserve the special static methods that are required in all enumeration
# classes.
-keepclassmembers class * extends java.lang.Enum {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
# You can comment this out if your application doesn't use serialization.
# If your code contains serializable classes that have to be backward
# compatible, please refer to the manual.
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# Your application may contain more items that need to be preserved;
# typically classes that are dynamically created using Class.forName:
# -keep public class mypackage.MyClass
# -keep public interface mypackage.MyInterface
# -keep public class * implements mypackage.MyInterface
優雅的混淆
僅供參考,思路類似
在需要保留的地方加上辨別@android.support.annotation.Keep
#手動啟用support keep注解
#http://tools.android.com/tech-docs/support-annotations
-dontskipnonpubliclibraryclassmembers
-printconfiguration
-keep @android.support.annotation.Keep class *
-keepclassmembers class * {
@android.support.annotation.Keep *;
}