在開發中混淆是app瘦身不可缺少的一部分。
官方說明
混淆其實是包括了代碼壓縮、代碼混淆以及資源壓縮等的優化過程。依靠 ProGuard,混淆流程將主項目以及依賴庫中未被使用的類、類成員、方法、屬性移除,這有助於規避64K方法數的瓶頸;同時,將類、類成員、方法重命名爲無意義的簡短名稱,增加了逆向工程的難度。而依靠 Gradle 的 Android 插件,我們將移除未被使用的資源,可以有效減小 apk 安裝包大小。
下面我就粗略的說下:
一. 混淆配置
一般情況下,app module 的 build.gradle 文件默認會有如下結構:
android {
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
因爲開啓混淆會使編譯時間變長,所以debug 模式下不應該開啓。我們需要做的是:
1.將release 下minifyEnabled 的值改爲true ,打開混淆;
2.加上shrinkResources true,打開資源壓縮。
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
二. 自定義混淆規則
在 app module 下默認生成了項目的自定義混淆規則文件 proguard-rules.pro ,多方調研後,一份適用於大部分項目的混淆規則最佳實踐如下:
#指定壓縮級別
-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 相互轉換的實體類。假如項目命名規範要求實體類都要放在model 包下的話,可以添加類似這樣的代碼把所有實體類都保持住:-keep public class .Model. {*;}
- JNI 中調用的類。
- WebView 中JavaScript 調用的方法
- Layout 佈局使用的View 構造函數、android:onClick 等。
這裏我以百度地圖爲例,你混淆的時候注意按照第三方的規則,切記不要混淆jar包
所以要加上
-keep class com.baidu.mapapi.** {*;}
-keep class com.baidu.** {*;}
-keep class vi.com.** {*;}
-dontwarn com.baidu.** //不混淆第三方jar
三. 檢查混淆結果
混淆過的包必須進行檢查,避免因混淆引入的bug。
一方面,需要從代碼層面檢查。使用上文的配置進行混淆打包後在 /build/outputs/mapping/release/ 目錄下會輸出以下文件:
- dump.txt
描述APK文件中所有類的內部結構 - mapping.txt
提供混淆前後類、方法、類成員等的對照表 - seeds.txt
列出沒有被混淆的類和成員 - usage.txt
列出被移除的代碼
我們可以根據 seeds.txt 文件檢查未被混淆的類和成員中是否已包含所有期望保留的,再根據 usage.txt 文件查看是否有被誤移除的代碼。
另一方面,需要從測試方面檢查。將混淆過的包進行全方面測試,檢查是否有 bug 產生。
注意事項:
1) 所有在 AndroidManifest.xml 涉及到的類已經自動被保持,因此不用特意去添加這塊混淆規則。(很多老的混淆文件裏會加,現在已經沒必要)
2) proguard-android.txt 已經存在一些默認混淆規則,沒必要在 proguard-rules.pro 重複添加
參考這裏寫鏈接內容