如何開啟混淆
eclipse
只需要在工程中找到projiect.properties檔案,在這個檔案中修改下面一段程式碼:
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt複製程式碼
Android Studio
在對應的module中,找到build.gradle,在該檔案中找到buildTypes,將minifyEnabled置成true,(有對gradle不熟悉的同學,可以參考這篇文章Android工程gradle詳解):
release {//release對應release編譯,debug對應debug編譯
// 是否進行混淆
minifyEnabled true
// 簽名檔案
signingConfig signingConfigs.debug
//對應的混淆檔案
proguardFiles 'proguard-rules.pro'
}複製程式碼
Proguard
Proguard是Android常用的免費的混淆工具,如果想了解混淆,需要先對Proguard進行了解
功能
Proguard主要提供瞭如下四種功能:
- 壓縮:Java原始碼通常被編譯為位元組碼,雖然位元組碼比原始碼更加簡潔,但它本身仍包含了很多無用的程式碼,Proguard通過分析位元組碼,去掉冗餘程式碼。
- 優化: 優化Java位元組碼,移除沒有使用到的指令
- 混淆: 使用無意義的字母對類名方法名,欄位名進行重新命名,達到混淆的效果
- 預檢驗: 對上述處理的程式碼進行與監獄
##基本配置
-dontusemixedcaseclassnames//不使用大小寫形式的混淆名
-dontskipnonpubliclibraryclasses//不跳過library的非public的類
-dontoptimize//不進行優化,優化可能會在某些手機上無法執行。
-dontpreverify//不淨行預校驗,該校驗是java平臺上的,對android沒啥用處
-keepattributes *Annotation*//對註解中的引數進行保留
-keep public class com.deep.test.MainActivity //對某個class不進行混淆
-dontshrink //不縮減程式碼,需要注意,反射呼叫的程式碼會被認為是無用程式碼而刪掉,所以要提前keep出來
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}//保持列舉類中的屬性不被混淆
-keepclassmemberspublic class xxx extends xxx{
void set*(***);
*** get*();
}不混淆任何view子類的get和set方法。
-keepclassmembers class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator CREATOR;
}//aidl檔案不能去混淆
-keep public class com.ebt.app.common.bean.Customer
//保留某個類名不被混淆
-keep public class com.ebt.app.common.bean.Customer { *;}
//保留類及其所有成員不被混淆
-keep public class com.ebt.app.common.bean.Customer {
static final;
private void get*();
}//只保留類名及其部分成員不被混淆
-keep class com.ebt.app.sync.** { *;}
//保留包路徑下所有的類及其屬性和方法
-keepclassmembers class **.R$* {
public static ;
}//資源類變數需要保留複製程式碼
下面會對上面提到過的關鍵字進行介紹:
- keep:包留類和類中的成員,防止他們被混淆
- keepnames:保留類和類中的成員防止被混淆,但成員如果沒有被引用將被刪除
- keepclassmembers:只保留類中的成員,防止被混淆和移除。
- keepclassmembernames:只保留類中的成員,但如果成員沒有被引用將被刪除。
- keepclasseswithmembers:如果當前類中包含指定的方法,則保留類和類成員,否則將被混淆。
- keepclasseswithmembernames:如果當前類中包含指定的方法,則保留類和類成員,如果類成員沒有被引用,則會被移除。
- -dontwarn:忽視警告。
- -optimizationpasses 5:proguard對你的程式碼進行迭代優化的次數,首先要明白optimization 會對程式碼進行各種優化,每次優化後的程式碼還可以再次優化,所以就產生了 優化次數的問題,這裡面的 passes 應該翻譯成 ‘次數’
- -keepattributes Signature:避免混淆泛型。
- -keepattributes SourceFile,LineNumberTable:丟擲異常時保留程式碼行號
一些符號的解釋說明
構造方法
所有成員
所有方法
所以所有成員不被混淆可以這麼寫
-keepclasseswithmembers class com.ebt.app.common.bean.Customer {
<init>;
<field>;
<methods>;
}複製程式碼
你還可以在
-keepclasseswithmembers class com.ebt.app.common.bean.Customer {
public <init>;
public <field>;
public <methods>;
}複製程式碼
還可以再加一些限制(以JSONObject型別作為引數的構造方法不進行混淆):
-keepclasseswithmembers class com.ebt.app.common.bean.Customer {
public <init>(org.json.JSONObject);
}複製程式碼
防止jni的方法被混淆
-keepclasseswithmembernames class * { # 保持native方法不被混淆
native <methods>;
}複製程式碼
- $如果我們要保留一個類中的內部類不被混淆則需要用$符號
? 匹配單一的字元
*匹配一段字元
%匹配基本型別
-libraryjars libs/aaa.jar 不混淆某個jar
##注意事項- 反射用到的類不混淆(否則反射可能出現問題);
- AndroidMainfest中的類不混淆,所以四大元件和Application的子類和Framework層下所有的類預設不會進行混淆。自定義的View預設也不會被混淆;所以像網上貼的很多排除自定義View,或四大元件被混淆的規則在Android Studio中是無需加入的;
- 與服務端互動時,使用GSON、fastjson等框架解析服務端資料時,所寫的JSON物件類不混淆,否則無法將JSON解析成對應的物件;
- 使用第三方開源庫或者引用其他第三方的SDK包時,如果有特別要求,也需要在混淆檔案中加入對應的混淆規則;
- 有用到WebView的JS呼叫也需要保證寫的介面方法不混淆;
- Parcelable的子類和Creator靜態成員變數不混淆,否則會產生Android.os.BadParcelableException異常
-keep class * implements Android.os.Parcelable { // 保持Parcelable不被混淆
public static final Android.os.Parcelable$Creator *;
}複製程式碼
- 使用enum型別時需要注意避免以下兩個方法混淆,因為enum類的特殊性,以下兩個方法會被反射呼叫,見第二條規則。
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}複製程式碼