為什么需要優(yōu)化包體積
- 下載轉化率灾螃,包體積增加不利于用戶下載
- 推廣成本凿试,包體積增大推廣成本也會加大
- 應用市場限制
包體積與性能
- 安裝時間匹舞,文件拷貝褐鸥、Library解壓、編譯ODEX策菜,簽名校驗等隨著包體積增大晶疼,耗時也會相應增加
- 運行內存酒贬,Resource資源又憨、Library以及Dex類加載這些都會占用不少內存
- ROM空間,如果閃存空間不足锭吨,非常容易出現寫入放大的情況蠢莺。
包體積優(yōu)化
海外Google Play市場,可以根據用戶的ABI零如、density和language發(fā)布躏将,也可以使用App Bundle。
1考蕾、代碼
ProGuard
仔細檢查配置文件祸憋,尤其是第三方SDK,是不是存在過度keep的現象肖卧。一般來說蚯窥,應用都會keep住四大組件以及View的部分方法,這樣是為了再代碼和XML布局中可以引用到它們塞帐。事實上拦赠,我們完全可以把非exported的四大組件以及View混淆,但是需要完成下面幾個工作:
- XML替換葵姥,在代碼混淆之后荷鼠,需要同時修改AndroidManifest以及資源文件XML中引用的名稱。
- 代碼替換榔幸,需要遍歷其他已經混淆好的代碼允乐,將變量或者方法體中定義的字符串也同時修改。需要注意的是削咆,代碼中不能出現經過運算得到的類名牍疏,這種情況會導致替換失敗。
去掉Debug信息或者去掉行號
DebugItem里面主要包含兩種信息:
- 調試的信息态辛,函數的參數變量和所有的局部變量
- 排查問題的信息麸澜,所有的指令集行號和源文件的對應關系。
Dex分包
如下圖所示如果將Class A與Class B分別編譯到不同的Dex中奏黑,由于method a 調用了method b炊邦,所以在classes2.dex中也需要加上method b的id编矾。
因為跨dex調用造成的這些冗余信息,它對Dex的大小會造成如下影響:
- method id爆表馁害,每個Dex的method id需要小于65536窄俏,因為method id的大量冗余導致每個Dex真正可以放Class變少,這是造成最終編譯的Dex數量增多
- 信息冗余碘菜,因為我們需要記錄跨Dex調用的方法的詳細信息凹蜈,所以classes2.dex還需要記錄Class B以及method b的定義,造成string_ids忍啸、type_ids仰坦、proto_ids這幾部分信息的冗余。
Dex壓縮
逆向Facebook的App時會驚訝的發(fā)現计雌,它只有一個700多KB的Dex悄晃,事實上Facebook APP的dex只是一個殼,真正的代碼都放到assets下面凿滤,它們把所有的Dex都合并成同一個secondary.dex.jar.xzs文件妈橄,并通過XZ壓縮。
XZ壓縮算法和7-Zip一樣內部使用的都是LZMA算法翁脆,對于Dex格式來說眷蚓,XZ的壓縮可以比Zip高30%左右。這套方案似乎存在一些問題:
- 首次啟動解壓反番,應用首次啟動時沙热,需要將secondary.dex.jar.xzs解壓縮,Facebook使用多線程解壓的方式恬口,這個耗時在高端機是幾百毫秒左右校读,在低端機可能需要3~5秒。
-
ODEX文件生成祖能,當Dex非常多的時候回增加應用安裝時間歉秫,對于Facebook的這個做法,首次生成ODEX的時間可能會達到分鐘級养铸。Facebook為解決這個問題雁芙,使用了ReDe的oatmeal。
oatmeal的原理非常簡單钞螟,就是更具ODEX文件的格式兔甘,自己生成一個ODEX文件,它生成的結果跟解釋執(zhí)行的ODEX一樣鳞滨,內部是沒有機器碼的洞焙。
2、Native Library
Library壓縮
跟Dex壓縮一樣,Libray優(yōu)化的有效方法就是使用XZ或者7-Zip壓縮澡匪。Facebook有一個So加載的開源庫SoLoader熔任,它可以跟改套方案配合使用。和Dex壓縮一樣唁情,壓縮方案的主要缺點在于首次啟動的時間疑苔,畢竟對于低端機來說,多線程的意義不大甸鸟,一次我們要再包體積和用戶體驗之間做好平衡惦费。
Library合并與裁剪
- Library合并,在Android4.3之前抢韭,進程加載的Library數量是有限制的薪贫,在編譯過程,可以自動將部分Library合并成一個篮绰。
-
Library裁剪后雷,Buck里面有個relinker的功能,原理就是分析代碼中JINI方法以及不同Library的方法調用吠各,找到沒有使用的導出symbol,將它們刪掉勉抓,這樣linker在編譯的時候也會把對應的無用代碼同時刪除贾漏。
AndResGuard工具
1、資源混淆
ProGuard的優(yōu)化核心主要有三個:Shrink藕筋、Optimize和Obfuscate纵散,也就是裁剪、優(yōu)化和混淆隐圾。資源混淆的思路其實非常簡單伍掀,就是把資源文件和文件的名字混淆成短路徑,這樣做有如下優(yōu)化作用:
- resources.arsc暇藏,因為資源文件resources.arsc需要記錄資源文件的名稱與路徑蜜笤,使用混淆后的段路徑,可以減少整個文件的大小盐碱。
- metadata簽名文件把兔,簽名文件MF與SF都需要記錄所有文件的路徑及它們的哈希值,使用短路徑可以減少這兩個文件的大小瓮顽。
- ZIP文件索引县好,ZIP文件格式里面也需要記錄每個文件的Entry的路徑、壓縮算法暖混、CRC缕贡、文件大小等信息,使用短路徑本身就可以減少記錄文件路徑的字符串大小。
2晾咪、極限壓縮
- 更高的壓縮率
- 壓縮更多的文件
資源合并
在資源混淆方案中黔漂,發(fā)現資源文件的路徑對于resources.arsc、簽名信息以及ZIP文件信息都會有影響禀酱,而且資源文件數量非常之多炬守,導致這部分體積非常客觀剂跟。
那我們能否將所有資源文件都合并成同一個大文件减途,這樣做肯定會比資源混淆方案更好。事實上大部分的換膚方案也是采用這個思路曹洽,這個大資源文件就相當于一套資源文件鳍置。
- 資源的解析,我們需要模擬系統實現資源文件的解析送淆,例如把PNG税产、JPG以及文件轉換為Bitmap或者Drawable,這樣獲取資源文件的方法需要改成我們自定義的方法偷崩。
- 資源的管理辟拷,考慮到內存和啟動時間,所有的資源有是用時架子阐斜,我們需要使用mmap來加載“Big resource File”衫冻,同時還要實現自己的資源緩存池ResourceCache,釋放不再使用的資源文件谒出。
無用資源
- Lint
- shrindResources