android基礎知識--混淆的記錄

在開發中混淆是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 重複添加

參考這裏寫鏈接內容

發佈了116 篇原創文章 · 獲贊 30 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章