由於工作需要,這兩天和同事在研究android下面的ProGuard工具的使用,通過查看android官網對該工具的介紹以及網絡上其它相關資料,再加上自己的親手實踐,算是有了一個基本了解。下面將自己的理解和認識簡要的做個筆記,有異議或者不解的,可以直接留言。
什么是ProGuard工具?
ProGuard是android提供的一個免費的工具,它能夠移除工程中一些沒用的代碼,或者使用語義上隱晦的名稱來重命名代碼中的類、字段和函數等,達到壓縮、優化和混淆代碼的功能。具體來說,使用ProGuard工具,可以達到下面兩個目的:
- 刪除了源文件中沒有調用的那部分代碼,最大化的精簡了字節碼文件,使得最終生成的apk文件更小。
- 使用語義混淆的命名替換了代碼中的類、字段和函數等,使得其他人無法反編譯獲取源代碼,起到對代碼的保護作用。
我看網上有不少人根據ProGuard工具的作用,直接稱呼其為“混淆代碼工具”,本文也暫時用這個詞簡稱。
更多的理解,可以參考ProGuard工具的官方文檔地址:http://developer.android.com/tools/help/proguard.html
ProGuard工具的集成與使用環境
其實,ProGuard工具是已經集成到我們android系統中的,所以不需要用戶手動的去集成。但是有一點需要注意,僅在程序處於Release模式時ProGuard才有效,反之在Debug模式是不能通過ProGuard來混淆代碼的。
根據ProGuard的具體使用環境,我分在Eclipse工具和android源碼兩種編譯環境淺談ProGuard的使用方法。
Eclipse環境中ProGuard的使用
以我電腦的android4.0環境為例,當我們在Eclipse中新建一個項目,或者導入一個已存在項目(保證當前項目沒有語法錯誤)后,在工程的根目錄,會自動生成兩個ProGuard的混淆文件:proguard-project.txt和project.properties(在老版本的ADT中,只會生成一個叫proguard.cfg的文件)。我們先看下文件project.properties :
看后面一段注釋:To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home) ,意指要讓ProGuard 來壓縮和混淆代碼,把這句注釋去掉即可!所以,我們只要把下面一句注釋取消即可,如下所示:
我們仔細的看下這部分代碼:這個地方是通過設置proguard.config屬性來指定混淆代碼的配置文件為本機SDK目錄下面的proguard-android.txt文件,以及制定混淆的個性化配置文件為當前工程(eclipse下)根目錄下面的proguard-project.txt文件 ,而后面這個文件,恰是我們剛才看到的原本在根目錄下自動生成的另外一個文件!
其實打開了這個地方,我們就已經可以混淆代碼了,不過這里要注意:不能試圖通過運行eclipse中的Run as 和 Debug as 菜單來生成混淆代碼,必須通過如下圖所示的方法將apk導出才行,當然你可以選擇“簽名”或者“不簽名”:

這樣一步操作后,算是代碼混淆完成了。那么怎么才能檢驗我們真的混淆了代碼了呢?首先,我們能夠看到在工程的根目錄新生產了一個文件夾proguard,里面有四個文件,其內容如下:
- dump.txt : 描述了apk中所有類 文件中內部的結構體。( Describes the internal structure of all the class files in the .apk file )
- mapping.txt : 列出了原始的類、方法和名稱與混淆代碼見得映射。( Lists the mapping between the original and obfuscated class, method, and field names. )
- seeds.txt : 列出了沒有混淆的類和方法。( Lists the classes and members that are not obfuscated )
- usage.txt : 列出congapk中刪除的代碼。( Lists the code that was stripped from the .apk )
同時使用反編譯軟件對新生成的apk反編譯后會發現,里面的類名、方法和變量等,都變成了簡單的a、b、c、d等毫無含義的字母,這樣就達到了混淆的目的:
但在實際使用過程中,我們會發現當前apk中的有些方法和類,是要供外部使用的,而此時混淆了名稱,外部調用就會報錯了,那么怎么解決這個問題?此時就要用到我們剛才提到的混淆的個性化配置文件proguard-project.txt,在其中去配置不需要混淆的類、方法和變量等。關於混淆文件的具體配置方法,請看下面的最后一個標題會有詳述。
Android源碼環境中ProGuard使用
在Google發布的android源碼中,面對那么多代碼和文件目錄,此時該如何混淆代碼與配置混淆文件呢?
android中默認是將代碼混淆ProGuard關閉的,在alps/build/core/proguard.flags中有下面一句,意指將默認不混淆,不需要代碼刪除,我們將這一句注釋起來,就起到代碼混淆編譯的作用。
可以說,這句是android工程中代碼混淆的總開關,然而,注釋了上面的代碼后,整個工程就已經是代碼混淆了嗎?不是的,這里還要關注一個文件alps/build/core/package.mk,在這個文件中有這么一段:
切記:當我們需要對整個工程進行代碼混淆的時候,就把此處的 #LOCAL_PROGUARD_ENABLED :=full注釋去掉,成為有效的宏即可。如果不想對整個工程代碼混淆,而只是相對某個模塊混淆的話,就先不要動這里的代碼。
接着建議將真個工程new一遍,之后就可以針對具體的apk文件進行混淆文件的設置和定制了。下面以alps/packages/apps/Music為例說說該如何對特定模塊做到混淆代碼:
在Music目錄下,我們看到一個平時不太關注,但今天一定很在意的文件名:proguard.flags ,對了,這個文件就是Music的混淆配置文件,可以打開看看(有些地方沒有這個文件,用戶可以自己手動新建一下,最好名稱也叫proguard.flags,android下默認都是這個名字)。當然,設置了配置文件還是不夠的,還需要在同目錄的Android.mk中如下設置如下兩句:
只有這樣才能讓混淆代碼有效,並且將混淆配置文件關聯起來。(有些模塊沒有這兩句句,就自己手動加上)
反之,如果用戶已經在alps/build/core/package.mk打開了全工程混淆編譯的控制點后,又在針對某個模塊時不想混淆編譯怎么辦?這就簡單了,將模塊下的Android.mk中設置為**LOCAL_PROGUARD_ENABLED := disabled**即可。
這樣,我們通過mm編譯后的代碼生成的apk,或者new真個工程后生成的燒機代碼,都是已經添加相應配置的混淆代碼了。
反編譯后,除過proguard.flags中定制的不需要混淆的代碼外,其他都是被混淆了,如圖所示是android中Music模塊的混淆后反編譯結果:

混淆文件的配置
在實際使用過程中,我們會發現當前apk中的有些方法和類,是要供外部使用的,而此時混淆了名稱,外部調用就會報錯了,那么怎么解決這個問題?此時就需要我們配置混淆的個性化文件proguard-project.txt(eclipse環境中)或者proguard.flags(android源碼環境),在其中去配置不需要混淆的類、方法和變量等。關於混淆文件的具體配置方法,大家可以去搜索下,我這里提供一段網上有人共享的配置代碼,這個配置代碼保留了工程文件中的Activity、Application、Service、BroadcastReceiver、ContentProvider、BackupAgentHelper、Preference和ILicensingService的子類,並保留了所有的Native變量名及類名,所有類中部分以設定了固定參數格式的構造函數,枚舉等等,用來防止外部調用出錯,大家可以借鑒下,以后來配置自己的文件:
