在 Gradle For Android(二) 多渠道打包與簽名配置中說過在平常開發中進行打包apk的一些往事,打包測試、打包上傳應用商店,這些都避免不了。固然在這過程當中,除了簽名打包,固然少不了代碼的混淆了。代碼混淆,說白了就是代碼壓縮、代碼混淆以及資源壓縮的優化。依靠 ProGuard,將全部類名、方法名重命名爲無心義的簡單名稱,增長了逆向工程難度。依靠Gradle插件,移除了沒有使用的資源,減小了apk大小 。java
通常,在咱們的application moudle中的gradle配置項buildTypes中,例如以下:android
release { //release類型
minifyEnabled false
// 啓用混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}複製代碼
這裏minifyEnabled表示啓動混淆,通常啓動混淆編譯速度會比較慢,所以在編譯debug版本的時候通常默認不開啓。proguard-rules.pro這個表示該module默認的混淆文件,咱們能夠直接將混淆內容寫在這裏。另外,這裏也要說下shrinkResources 這個字段,當爲true的時候,表示打開資源壓縮,編譯時會去掉沒被使用的資源文件。git
修改後的配置代碼以下:github
buildTypes {//表示構建類型 通常有release debug 兩種
debug{
buildConfigField 'String','STATE_TEST','"debug"'//buildConfigField
resValue "string", "test_value", "AGradle_debug"//resValue
}
release { //release類型
minifyEnabled true // 啓用混淆
shrinkResources true // 資源壓縮
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField 'String','STATE_TEST','"release"' //buildConfigField
resValue "string", "test_value", "AGradle_release" //resValue
}
}複製代碼
這裏貼下網上認爲比較"通用"的混淆規則以下:算法
#指定壓縮級別
-optimizationpasses 5
#不跳過非公共的庫的類成員
-dontskipnonpubliclibraryclassmembers
#混淆時採用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#把混淆類中的方法名也混淆了
-useuniqueclassmembernames
#優化時容許訪問並修改有修飾符的類和類的成員
-allowaccessmodification
#將文件來源重命名爲「SourceFile」字符串
-renamesourcefileattribute SourceFile
#保留行號
-keepattributes SourceFile,LineNumberTable
#保持全部實現 Serializable 接口的類成員
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
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();
}
#Fragment不須要在AndroidManifest.xml中註冊,須要額外保護下
-keep public class * extends android.support.v4.app.Fragment
-keep public class * extends android.app.Fragment
# 保持測試相關的代碼
-dontnote junit.framework.**
-dontnote junit.runner.**
-dontwarn android.test.**
-dontwarn android.support.test.**
-dontwarn org.junit.**複製代碼
"通用",固然真正實現通用,除了上面的混淆規則,須要根據項目須要添加自定義的混淆規則json
例如:api
第三方庫混淆規則。這個比較常見,直接接入官方說明文檔。app
model實體類,典型在轉化json的時候,必須保證model不被混淆,所以需加入--keep public class函數
JNI中調用的類以及方法不可被混淆佈局
WebView中JavaScript調用的接口不混淆
AndroidMainfest、四大組件以及Application的子類不混淆
Parcelable的子類和Creator靜態成員變量不混淆,不然會產生Android.os.BadParcelableException異常
Layout佈局使用的View構造函數、android:onClick等。
3、混淆結果的檢測
在開啓混淆後,經過混淆配置打包後,會在目錄:
/outputs/mapping/ <渠道名> / <編譯類型> /.. 複製代碼
如圖所示:
下面大概說明下:
咱們能夠根據 seeds.txt 文件檢查未被混淆的類和成員中是否已包含全部指望保留的,再根據 usage.txt 文件查看是否有被誤移除的代碼。建議讀者都試下去查看下,必須有收穫~
include {filename} 從給定的文件中讀取配置參數
basedirectory {directoryname} 指定基礎目錄爲之後相對的檔案名稱
injars {class_path} 指定要處理的應用程序jar,war,ear和目錄
outjars {class_path} 指定處理完後要輸出的jar,war,ear和目錄的名稱
libraryjars {classpath} 指定要處理的應用程序jar,war,ear和目錄所須要的程序庫文件
dontskipnonpubliclibraryclasses 指定不去忽略非公共的庫類。
dontskipnonpubliclibraryclassmembers 不跳過非公共的庫的類成員
上面部分參數,平常移動開發的應用混淆中也不是常用到的,若是讀者想進一步深刻了解每一個參數實際做用,能夠去官網進行查閱,這裏筆者不作太多說明哈。
######(二)keep 參數
keep {Modifier(屬性,例如public,如下說明一致)} {class_specification(具體類或者成員的位置,如下說明一致)} 防止類和成員被移除或者被重命名
keepclassmembers {modifier} {class_specification} 防止成員被移除或者被重命名
keepnames {class_specification} 防止成員被重命名)
keepclassmembernames {class_specification} 防止擁有該成員的類和成員被移除或者被重命名
keepclasseswithmembernames {class_specification} 防止擁有該成員的類和成員被重命名
一、通常規則形式:
[命令] [類] {
[成員]
}複製代碼
類:表明相關指定條件的類,例如
public
、protected
、private
)*
,匹配任意長度字符,但不含包名分隔符(.)**
,匹配任意長度字符,而且包含包名分隔符(.)extends
,便可以指定類的基類implement
,匹配實現了某接口的類成員:表明指定類後符合指定條件的成員變量,例如
*
,匹配任意長度字符,但不含包名分隔符(.)**
,匹配任意長度字符,而且包含包名分隔符(.)***
,匹配任意參數類型…
,匹配任意長度的任意類型參數。好比void test(…)就能匹配任意 void test(String a)
或者是 void test(int a, String b)
這些方法。public
、protected
、private
)舉個例子,假如須要將name.huihui.test
包下全部繼承Activity
的public
類及其構造函數都保持住,能夠這樣寫:
-keep public class name.huihui.test.** extends Android.app.Activity {} 複製代碼
二、經常使用自定義混淆規則
-keep public class name.huihui.example.Test { *; }複製代碼
-keep class name.huihui.test.** { *; }複製代碼
-keep public class * extends name.huihui.example.Test { *; }複製代碼
-keep public class **.*model*.** {*;}複製代碼
-keep class * implements name.huihui.example.TestInterface { *; }複製代碼
-keepclassmembers class name.huihui.example.Test { public(); } 複製代碼
-keepclassmembers class name.huihui.example.Test {
public void test(java.lang.String);
}複製代碼
前面說的經過shrinkResources true開啓資源壓縮後,未被使用的資源默認不會被打包進去。若是開發者是自定義保留指定的資源文件,能夠在res/raw/
路徑下建立一個 xml 文件,例如 keep.xml
,進行自定義混淆規則。
通常屬性有:
tools:keep
定義哪些資源須要被保留(資源之間用「,」隔開)tools:discard
定義哪些資源須要被移除(資源之間用「,」隔開)tools:shrinkMode
開啓嚴格模式例如:
複製代碼
最後感謝@ 光源coder提供的混淆手冊,總結的不錯~
但願對有些開發者有幫助~具體查看能夠github上的demo,也歡迎加入開發交流羣哈,詳情看我的簡介。下一篇是對gradle的混淆說明,歡迎讀者閱讀~
Gradle For Android(四)Gradle編譯中神祕的混淆
傻小孩b mark共勉,寫給在成長路上奮鬥的你