還是老外文章質(zhì)量高:ProGuard 在 Android 上的使用姿勢
progurad是對編譯后的class字節(jié)碼進行處理秉宿。
在android studio中通過一行代碼設(shè)置混淆配置文件:
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
這行代碼的意思是配置文件使用proguard-android.txt和proguard-rules.pro兩個文件。從andrid gradle plugin2.2開始妖谴,proguard-android.txt文件runtime時生成酌摇。里面設(shè)置了一些基本配置。
proguard-android.txt文件中關(guān)閉了optimize仍稀,所以通常情況下progurad對android工程主要是兩個功能shrink&obfuscate即壓縮和混淆技潘。壓縮單純是對代碼壓縮,移除未被使用的code享幽,壓縮之后再進行通過簡化類名拾弃、變量、方法的形式進行代碼混淆奔坟。
注意真正打到j(luò)ar里面的類才會被混淆,android.jar這種東西是供我們調(diào)用的本身不會被打到我們的jar里咳秉,所以不會被混淆。library module中使用的第三方庫由于最終打aar的時候不會被打進去所以也不會被混淆向挖。所以你會看到我們代碼中對這些類的使用和import都是正常類名炕舵。混淆是對Class帝美、field進行重命名晤硕,同時import或者引用它的地方也會被新的名字替換庇忌。library module如果是做為一個module library被主工程引用,那么混淆規(guī)則也必須加到主工程里或者設(shè)置compileProgurad屬性疏橄。如果是先打包出來aar略就,那么aar是會被混淆的,然后混淆后的aar被主工程引用窄绒。
另外說一下資源的問題崔兴,library module的資源R文件中的id不是final的,aapt在打包apk的時候會對資源進行merge位谋,如果資源重名則會remove掉優(yōu)先級低的模塊的資源堰燎。最終apk包里每種類型的資源里,一個資源名字只有一份資源對應(yīng)一個id损同。具體可以看下這個
默認配置文件proguard-android.txt并沒有對android四大組件做keep,但是如果組件在androidmanifest中聲明了就不會被混淆膏燃,未聲明的會被混淆。
support庫因為屬于第三方庫會被打到j(luò)ar中(library module不會)等龙,所以如果沒有設(shè)置keep也會被混淆伶贰。
混淆最大的好處是加密,最大的壞處是容易因為使用不當導(dǎo)致諸如ClassNoFound異常泥畅。因此以下幾種場景需要設(shè)置keep防止發(fā)生這種異常:
- 需要提供給外部的接口肯定不能混淆琅翻,常見sdk。
- 第三方開源庫通常不需要混淆方椎,主要原因是沒有必要,人家本來就開源琳疏,萬一混淆自找麻煩闸拿。
- 自己代碼中用到了反射,則不能混淆被你發(fā)射的類
- 其它
大坑(Instant Run)
看proguard這塊東西的時候經(jīng)常有提到InstantRun模式下proguard不生效但具體沒理解也沒去關(guān)注揽趾。直到一次很正常的debug模式下打開混淆后直接點擊run按鈕運行應(yīng)用崩潰了迟隅,提示找不到activity”疾看混淆配置沒啥問題吼野,試了命令行安裝運行應(yīng)用正常才懷疑是不是InstantRun搞的鬼,關(guān)閉InstantRun后再點擊run一切正常闷哆。發(fā)現(xiàn)開啟InstantRun之后似乎編譯的話會混淆但是忽略你的混淆設(shè)置。你反編譯apk看不出來什么異常劣坊。
Android Studio build目錄下有很多文件供我們了解proguard的情況屈留,mapping目錄的mapping.txt seeds.txt usage.txt以及intermediates目錄下的proguard-rules/aapt_rules. 以及javac目錄下可以方便查看混淆后的class文件。
proguard的shrink會對未使用的代碼remove康二,最終可以在usage.txt看到哪些東西被remove掉了勇蝙。正常在對代碼shrink后可以通過設(shè)置shinkResources利用lint來移除未使用資源。但是對于library module是不支持這個屬性的产雹,所以可以手動通過as的inspect對module進行check惜傲,手動remove掉lint result中提示的unused resource贝攒。lint本身包含非常多的項目,unused resource只是其中一項而已哈踱。
build這個task包括assemble&check梨熙,如果在build.gradle中設(shè)置了lintOption{abortOnerror true}那么執(zhí)行build如果遇到lint的error則build會被中斷,這通承安疲可以用來設(shè)置一些大家遵守的規(guī)則质欲,不遵守則不讓編譯通過。但是如果直接assemble則不會因為lint的error而中斷嘶伟。
使用apktool d解壓apk得到的value目錄中又一個public.xml這個就是merge后的資源表,里面每一行包括type绊袋、name、id三部分皂岔,是最終的結(jié)果展姐,apk具體使用哪個資源都是從這里面確定的。