Android開發(fā)之混淆高級教程:壓縮階段
上一篇文章介紹了混淆的基礎(chǔ)知識,包括保留指定的包名、類名、方法名以及字段名。本篇文章將重點介紹混淆的廣義概念,包括壓縮、優(yōu)化和混淆幾個階段。1. 壓縮階段在Java編譯時,源代碼(.java)會被轉(zhuǎn)換
上一篇文章介紹了混淆的基礎(chǔ)知識,包括保留指定的包名、類名、方法名以及字段名。本篇文章將重點介紹混淆的廣義概念,包括壓縮、優(yōu)化和混淆幾個階段。
1. 壓縮階段
在Java編譯時,源代碼(.java)會被轉(zhuǎn)換成字節(jié)碼(.class),相比源代碼,字節(jié)碼更加簡潔。然而,生成的字節(jié)碼中可能包含一些沒有用到的代碼,特別是當(dāng)項目中使用了第三方類庫時,未引用的代碼會更多。
壓縮階段會分析生成的字節(jié)碼,在確保項目正常運行的同時移除一些未引用的類、字段和方法。為了驗證移除未引用代碼的效果,我們創(chuàng)建一個module,包含AdvancedCourseActivity和Subject兩個類,其中Subject沒有被引用。
對混淆后的項目進行簽名打包,并反編譯生成的apk文件,檢查是否仍然存在Subject的字節(jié)碼文件。
2. 反編譯結(jié)果
反編譯后的項目結(jié)構(gòu)如下:
由以上結(jié)果可見,Subject的字節(jié)碼文件已被成功移除。
3. 引用代碼
接下來我們修改Subject類中的代碼如下:
然后在AdvancedCourseActivity中引用Subject提供的構(gòu)造方法和get方法。我們想知道未被引用的set方法是否會被移除。
4. 反編譯結(jié)果再次分析
反編譯后的項目結(jié)構(gòu)如下:
從以上結(jié)果可見,混淆后僅保留了被引用的字段(courseName、creditHour)和方法(getCourseName()、getCreditHour()),以及構(gòu)造方法。我們將在后續(xù)的混淆中巧妙地使用壓縮規(guī)則,類似于Android Studio的App Link Assistant功能。
那么,如果我們不想執(zhí)行代碼的壓縮,該怎么做呢?這時候,我們需要學(xué)習(xí)一些壓縮階段的規(guī)則(除此之外,還有優(yōu)化規(guī)則和混淆規(guī)則)。
壓縮規(guī)則的可選項包括以下幾種:
1. -dontshrink:開啟混淆,默認壓縮所有類。通過添加該關(guān)鍵字,可關(guān)閉壓縮過程。在文件中添加以下規(guī)則:
5. 反編譯結(jié)果再次分析
反編譯后的項目結(jié)構(gòu)如下:
由上圖可見,壓縮階段已被關(guān)閉,Subject的字節(jié)碼文件仍然存在。
2. -printusage [filename]:將壓縮階段未引用的所有類信息打印到指定文件中。如果未在中指定該選項,則默認輸出到路徑:
在上述示例中,Subject的set方法未被引用,在usage.txt文件中可以找到相關(guān)信息。這一功能可用于檢查簽名打包后,在壓縮階段移除了哪些代碼,并驗證是否符合要求。
3. -whyareyoukeeping class_specification:打印保留類和內(nèi)部成員的詳細說明。class_specification指定需要了解的類名。詳細說明將在Gradle控制臺查看。例如,我們想了解為什么保留Subject類信息,可在文件中添加以下規(guī)則:
運行當(dāng)前項目后,Gradle控制臺將顯示如下信息:
以上信息表明Subject類被引用了setCourseName()和setCreditHour()方法,以及get方法和構(gòu)造方法。在AdvancedCourseActivity的void onCreate()方法中進行了調(diào)用。
至此,我們完成了壓縮階段的學(xué)習(xí)。