### 背景
隨著業務快速發展,各種業務功能上線,版本不斷迭代,apk體積也越來越大。apk體積過大,一方面會消耗用戶更多的流量,另一方面也會增加包安裝時間,進而對于app流量導入產生不利影響。
> 在動手之前,還是要考慮清楚:什么是apk體積過大,閾值是多少?建議結合實際目標用戶群體和市場中類似app想對比,定義一個合適值。如果用戶90%都是在WIFI場景下,而實際包體積只有20M,推斷用戶僅需要20s時間就能安裝完成,相信很多用戶還是愿意去等的。技術千萬不能為了技術而技術。
### Apk構成
首先我們看下apk是什么?下面是來自wiki的定義:
> Android應用程序包(英語:Android application package,APK)是Android操作系統使用的一種應用程序包文件格式,用于分發和安裝移動應用及中間件。一個Android應用程序的代碼想要在Android設備上運行,必須先進行編譯,然后被打包成為一個被Android系統所能識別的文件才可以被運行,而這種能被Android系統識別并運行的文件格式便是“APK”。 一個APK文件內包含被編譯的代碼文件(.dex 文件),文件資源(resources), assets,證書(certificates),和清單文件(manifest file)。
通過上面解釋,我們可以大致了解apk的構成。實質上apk仍然是一個壓縮包,符合zip標準。在以前,我們可以把后綴名改成`.zip`再解壓開來進行分析?,F在AS提供了新的工具可以直接Analyze Apk,在AS中雙擊build目錄下的apk或通過menu中的Build菜單找到apk源文件即可。
我們看一個實際的例子:
通過工具,我們看到各個部分的體積大小,以及占的百分比,幫助我們優化更加有的放矢。
#### dex優化
我們知道android應用是運行在虛擬機上的,工程編譯過程中會把java、aidl等文件編譯成class,再轉換成dex文件。如果method或field超過了65k,我們還需要引入multidex分包以保證在dialvik上正常運行。
常見的優化策略有無用代碼刪除,IDE會把未使用到的區塊灰色展示,也可以通過lint工具來幫助我們識別到。這個功能在menu中的Analyze的`Run inpection by name`輸入`unused xx`。甚至是在編譯過程中,我們也可以通過混淆配置來做到,比方說常見的Log刪除。
而隨著業務發展,大型app都進行了模塊化組件化,不同團隊負責開發不同模塊。開發過程極易出現一些重復工具方法,甚至引入相同功能的不同組件。架構上也需要一下規約工具來限定重復代碼的編寫。
在class轉換成dex過程中,我們可以用新一代d8工具,它可以幫助我們的dex體積更小運行速度更快。Facebook也開源了一款redex的工具幫助優化dex。
#### 資源優化
而說到資源必然要說的是圖片優化,畢竟圖片是資源體積中占大頭。
我們可以選擇體積更小的圖片,比方說webp格式。要注意的是,webp在4.3以下有一些兼容問題,選擇需謹慎。而對于png也可以采用有損或無損壓縮圖片,常見工具有tingpng或imageoptim等。經常png會有一些空白邊距,這些部分也可以刪除掉,通過代碼或xml來實現邊距。
小的icon也可以使用svg格式。一些特定效果也可以通過XML自定義實現。新手常常有個誤區,就是做.9圖片的原圖依舊很大,既然已經讓程序幫我們拉伸了,原圖實際上可以保持很小的體積。
經常在適配屏幕時,開發會使用多套圖片。實際上大部分時候一套圖片就可以搞定了,系統會自動幫我們處理圖片縮放。
而在適配不同API時,打包過程也會自動生成多個目錄。適當選擇最低API格式有好處的,更高版本意味著開發效率更高,同時兼容設備變少,需要同業務一起考慮。
打包過程也會生成一個resource.arsc文件,里面是資源ID的映射關系。這個部分也可以通過混淆資源id來優化,可以有效減少體積。
最后同樣的,不需要的資源一定要刪掉。同樣使用lint工具可以幫我們自動刪除。模塊化也需要當心不同模塊出現同樣的圖片。
#### 動態庫優化
在一些需要安全高性能的常見,應用中需要采用native來實現。android平臺提供了適配各種cpu架構的可能,包括x86 arm mips等,包活arm也有v7 v8等。針對不同cpu我們可以選擇打不同包,gradle腳本中通過api也可以限制。或者損失一些性能,只采用arm最低版本也是可以兼容的。對于某些不常用功能,我們也能用動態加載,運行時再下載so到本地。
### 持之以恒
包體積優化需要平常的積累,點點滴滴細節摳出來。需要每個版本都要注意,而不是到時候來個突擊。需要深入到每個人心中。針對app開發的生命周期,將一些步驟納入到流程匯總持續進行優化。從開發到測試再到上線,甚至是上線后app在設備上占的磁盤大小。