混淆代碼能有效防止項目被反編譯,同時還可以適當減少apk的大小,在實際開發過程中尤爲重要,經過長時間的摸索,對代碼混淆有了一定的瞭解,下面寫下個人心得:
1. 代碼混淆的重要文件:proguard-rules.pro,如果你不小心刪掉了,從其他地方複製一個或自己創建一個。
2. 開啓混淆:
將build.gradle下的buildTypes->release->minifyEnabled設置爲true,即可開啓代碼混淆
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
3. proguard-rules.pro文件中各項配置的含義
在配置之前先說明下一些含義
- -keep 保留目標不被混淆
- * 通配符,表示所有,擴展:set*表示以set開頭,*onEvent* 表示含有onEvent關鍵字
- <init> 表示構造方法
- <methods> 類裏面的方法
- <fields> 類裏面的屬性
- $ 分隔符,標識內部類
- -keepclasseswithmembers 保留類的成員
(配置項前加了#號表示註釋)
-optimizationpasses 5 # 指定代碼的壓縮級別
-dontusemixedcaseclassnames # 是否使用大小寫混合
-dontskipnonpubliclibraryclasses # 是否混淆第三方jar(建議註釋掉)
-dontpreverify # 混淆時是否做預校驗
-verbose # 混淆時是否記錄日誌
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* # 混淆時所採用的算法
-keep public class * extends **** # 保持哪些類不被混淆
-keepclasseswithmembernames class * { # 保持 native 方法不被混淆
native <methods>;
}
-keepclasseswithmembers class * { # 保持自定義控件類不被混淆
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int); # 保持自定義控件類不被混淆
}
-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 不被混淆
public static final android.os.Parcelable$Creator *;
}
#使用WebView時JavascriptInterface不被混淆,同時需要保證自定義的JS與原生交互的接口對象不被混淆
-keepattributes *JavascriptInterface*
#保證R文件不混淆
-keep public class [你的應用包名].R$*{ public static final int *;}
-keep class MyClass; # 保持自己定義的類不被混淆
4. 在proguard-rules.pro添加不需要混淆的代碼的申明:
a.將你不需要混淆的部分申明進來,有些類經過混淆會導致程序編譯不通過
-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 * extends android.support.v4.**
-keep public class com.android.vending.licensing.ILicensingService
以上都是android基本組件和依賴包
b. Model層(實體)的類建議不混淆
-keep class com.test.model.** { *; }
-keep class com.test.domain.** { *; } # 具體看實際項目包名和類
c.第三方的包都不建議混淆
第三方的library庫一般都已經混淆過,因此不必再次混淆
#示例:百度地圖SDK
-keep class com.baidu.** { *; }
-keep class vi.com.gdi.bgl.android.**{*;}
#其他第三方lib混淆規則請參照它們的官方文檔
總結來說就是用-keep加上你想要保留的東西。
下面介紹另一種快速配置混淆的方法,使用註解@Keep
1.在使用@Keep註解之前我們需要先導入
compile 'com.android.support:support-annotations:{version}'
2.在proguard-rules.pro添加以下配置
-dontwarn android.support.annotation.Keep
#保留註解
-keepattributes *Annotation*
-keep @android.support.annotation.Keep class ** #保留@Keep註解的類以及它的屬性方法不被混淆
3.在我們想要保留的東西上面使用@Keep註解
@Keep
public class Test {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在上面的代碼中,我們設置保留了Test這個類,那麼它在打包時就不會被混淆
如果我們只想保留它的屬性或者方法,類名混淆掉,那該怎麼辦呢?如下
在proguard-rules.pro修改如下配置:
-keep @android.support.annotation.Keep class **{
@android.support.annotation.Keep <fields>; #保留類裏面被@Keep註解的屬性
@android.support.annotation.Keep <methods>; #保留類裏面被@Keep註解的方法
}
然後在代碼中
public class Test {
@Keep
private String name;
@Keep
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
上面代碼中,保留了name這個屬性和getName()這個方法不被混淆,類名Test和方法名setName()依然會被混淆。
好了,代碼混淆總結差不多就這樣了,希望對大家有幫助!