性能優化專題五--Proguard混淆簡單使用、以及混淆後的映射

Proguard是一個代碼優化和混淆工具。能夠提供對Java類文件的壓縮、優化、混淆,和預校驗。壓縮的步驟是檢測並移除未使用的類、字段、方法和屬性。優化的步驟是分析和優化方法的字節碼。混淆的步驟是使用短的毫無意義的名稱重命名剩餘的類、字段和方法。壓縮、優化、混淆使得代碼更小,更高效。

一、Proguard簡單使用:

在build.gradle文件中默認的Proguard文件配置是false關閉的,我們可以在debug模式下打開,設置爲true即可:

默認的getDefaultProguardFile(‘proguard-android.txt’) 會使用build/intermediates/下面的文件(可以println 查看),如果在這個目錄下沒有則可以通過運行gradle任務:生成。而後面的’proguard-rules.pro’則是一個相對路徑,相對於這個build.gradle同級目錄下的proguard-rules.pro

然後在項目的gradle task中雙擊extractProguardFiles任務,就可以看到生成了三個混淆文件:

我們可以將proguard-android文件拷貝到我們項目中,看下系統生成的keep規則使用

可以看到不需要混淆的情況有如下一些:

  1. native層代碼;
  2. 所有繼承自view的組件;
  3. activity裏面的所有view;
  4. 枚舉;
  5. Parcelable;
  6. 靜態內部類;
  7. webkit接口;
  8. 所有support包、androidx下面的類;
  9. 所有使用了keep註解的類、方法、成員變量、構造方法

簡單語法:

-keep 指定類和類成員(變量和方法)不被混淆。

(保護了類名)
    -keep class com.dongnao.proxy.guard.test.Bug
(保護了 public static void的沒有參數的函數)
    -keep class com.dongnao.proxy.guard.test.Bug{
           public static void *();
    }
 (保護所有)
    -keep class com.dongnao.proxy.guard.test.Bug{
           *;
    }

-keepclassmembers 指定類成員不被混淆(就是-keep的縮小版,不管類名了)。

(都被混淆了)
-keepclassmembers class com.dongnao.proxy.guard.test.Bug

-keepclasseswithmembers 指定類和類成員不被混淆,前提是指定的類成員存在。

(保護類名,但是沒指定成員,所以函數名被混淆)    
-keepclasseswithmembers class com.dongnao.proxy.guard.test.Bug
-keepclasseswithmembers class       com.dongnao.proxy.guard.test.Bug{
        native <methods>;
  }

實驗項目地址https://github.com/buder-cp/base_component_learn/tree/master/performanceOPT/buderdn08

開啓混淆後,我們新建的User類,如果沒有使用到,那麼就不會打包到dex文件中,可以看到並沒有User類:

ProGuard 會移除所有(並且只會移除)未使用的代碼。不過,ProGuard 難以對許多情況進行正確分析,可能會移除應用真正需要的代碼。比如需要反射、動態加載所引用的類等情況,可能因爲proguard移除或者混淆了這部分沒使用的類,而導致錯誤。所以有時需要編寫混淆優化配置文件。在gradle中的proguardFiles 能夠讓我們傳遞File文件或者文件路徑交給proguard來執行。

當我們在MainActivity中使用這個User類後,

        User user = new User();
        user.age = 18;
        user.name = "buder";

並且添加混淆規則,不混淆User類裏面的String字段:

-keep class com.test.buderdn08.User {
    java.lang.String *;
}

最終的結果,User類中String成員變量是name,並沒有被混淆掉。

很多混淆命令可以多多嘗試使用。

二、Proguard生成的混淆代碼,如何對應原始代碼

outputs/mapping/debug/mapping.txt文件中保存了混淆前後的對應關係,混淆後的代碼錯誤棧恢復方法:

1.先配置  -keepattributes SourceFile,LineNumberTable

2.把錯誤信息保存到文件

3.使用工具 sdk/tools/groguard/bin/retrace.bat
再執行  retrace.bat  -verbose mappint文件  bug文件

我們在Activity中主動寫一個bug,運行產生這樣的日誌:

這個日誌有兩個問題:

  1. 我們不知道是哪個類報告出的。
  2. 不知道這個類是哪一行報出的。

第一個問題很顯然是由於我們的代碼進行了混淆。

在開啓混淆後,我們生成apk會產生

dump.txt:說明 APK 中所有文件的內部構。這個文件內容非常多,可性也並不高

mapping.txt:提供原始與混淆過、方法和字段名稱之間的轉換。

seeds.txt:列出未進行混淆的和成。我護的zip沒有被混淆

usage.txt:列出從 APK 移除的代碼。可以在這個文件中查看是不是有我們不想被移除的類

最重要的當然就是我們的mapping文件了。通過這個文件我們就能定位到:

出現錯誤的函數是Bug類中的test函數。

我們現在比較簡單,所以一下子就能定位到錯誤函數,如果函數層級較深,光靠自己比對來查找難度就比較大了。所以sdk中提供了一個工具在tools/proguard/bin中。

我們把logcat裏面保存的錯誤堆棧複製到一個文件中:

然後執行retrace 腳本(在 Windows 上爲 retrace.bat;在 Mac/Linux 上爲 retrace.sh)

retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]

現在錯誤日誌一句mapping還原了。所以我們每次在發佈版本之後都需要保留這個mapping文件。所以一般異常上報平臺都會提供mapping上傳然後幫助我們分析。

第一個問題解決的,第二個問題是行數顯示的是Unknow Source

如果希望出現具體行數,我們需要在配置文件中加入

拋出異常保留代行號,在異常分析中可以方便定位

-keepattributes SourceFile,LineNumberTable

另外還可以配合-renamesourcefileattribute AAA

使用字符串"AAA"來替代真正的,避免泄漏更多的信息

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章