前言
在 Android 效能優化的知識體系當中,包體積優化一直被排在優先順序比較低的位置,從而導致很多開發同學對自身應用的大小並不重視。在專案發展的歷程中,一般可劃分為如下三個階段:
初創期 => 成長期 => 成熟期通常來說,當應用處於成長期的中後階段時,才會考慮去做系統的包體積優化,因此,只有在這個階段及之後,包體積優化帶來的收益才是可觀的。
那麼,包體積優化能夠給我們帶來哪些 收益 呢?如何全面對應用的包體積進行 系統分析 及 針對性優化呢?我將編寫一個系列文章進行深入地分析與探索。
思維導圖大綱目錄一、瘦身優化及 Apk 分析方案1、瘦身優勢2、APK 組成3、APK 分析二、程式碼瘦身方案探索1、Dex 探祕2、ProGuard3、D8 與 R8 優化4、去除 debug 資訊與行號資訊5、dex 分包優化6、使用 XZ Utils 進行 Dex 壓縮7、三方庫處理8、移除無用程式碼9、避免產生 Java access 方法10、利用 ByteX Gradle 外掛平臺中的程式碼優化外掛11、小結三、資源瘦身方案探索1、冗餘資源優化2、重複資源優化3、圖片壓縮4、使用針對性的圖片格式5、資源混淆6、R Field 的內聯優化7、資源合併方案8、資原始檔最少化配置9、儘量每張圖片只保留一份10、資源線上化11、統一應用風格四、So 瘦身方案探索1、So 移除方案2、So 移除方案優化版3、使用 XZ Utils 對 Native Library 進行壓縮4、對 Native Library 進行合併5、刪除 Native Library 中無用的匯出 symbol6、So 動態下載五、其它優化方案1、外掛化2、業務梳理3、轉變開發模式六、包體積監控1、包體積監控的緯度七、瘦身優化常見問題1、怎麼降低 Apk 包大小?2、Apk 瘦身如何實現長效治理?八、**總結
下面,我們就先來了解下為什麼要進行瘦身優化以及如何對 Apk 大小進行分析。
一、瘦身優化及 Apk 分析方案介紹1、瘦身優勢我們首先來介紹下,為什麼我們需要做 APK 的瘦身優化?
APK 瘦身優化的原因主要有 三個方面 的原因:
1、下載轉化率APK 瘦身優化在實際的專案中優先順序是比較低的,因為做了之後它的好處不是那麼明顯,尤其是那些還沒有到 穩定期 的專案,我們都知道,App 的發展歷程是從 專案初期 => 成長期 => 穩定期,對於處於 發展初期與成長期 的專案而言,可能會做 啟動優化、卡頓優化,但是一般不會做 瘦身優化,瘦身優化最主要的好處是對應用 下載轉化率 的影響,它是 App 業務運營的重要指標之一,在專案精細化運營的階段是非常重要的。因為如果你的 App 與其它同類型的 App 相比 Apk 體積要更小的話,那麼你的 App下載率就可能要高一些。而且,包體積越小,使用者下載等待的時間也會越短,所以下載轉換成功率也就越高。所以,安裝包大小與下載轉化率的關係 大致是成反比 的,即安裝包越大,下載轉換率就越小。一個 80MB 的應用,使用者即使點了下載,也可能因為網路速度慢、突然反悔導致下載失敗。而對於一個 20MB 的應用,使用者點了下載之後,在猶豫要不要下的時候可能就已經下載完了。
而且,現在很多大型的 App 一般都會有一個 Lite 版本的 App,這個也是出於下載轉化率方面的考慮。
2、應用市場Google Play 應用市場強制要求超過 100MB 的應用只能使用 APK 擴充套件檔案方式 上傳。當使用 APK 擴充套件檔案方式 上傳時,Google Play 會為我們的應用 託管 擴充套件檔案,並將其 免費提供 給裝置。擴充套件檔案將儲存到裝置的共享儲存位置(SD 卡或可安裝 USB 的分割槽;也稱為“外部”儲存),應用可以在其中訪問它們。在大多數裝置上,Google Play 會在下載 APK 的同時下載擴充套件檔案,因此應用在使用者首次開啟時便擁有了所需的一切。但是,在某些情況下,我們的應用必須在應用啟動時從 Google Play 下載檔案。如果您想避免使用擴充套件檔案,並且想要應用程式的下載大小大於100 MB,則應該使用 Android App Bundles 上傳應用程式,此時應用程式最多可提供150 MB的壓縮下載大小。Android App Bundles 就是 Android 應用程式捆綁包,它能夠讓 App 以 新增動態功能模組的方式 去解決 APK 大小較大的問題。如下,就是由一個基本模組和兩個動態功能模組組成的 Android App Bundle APK 的組成結構圖:
3、渠道合作商的要求此外,還有一個原因,當我們的 App 做大之後,可能需要跟各個手機廠商合作預裝,這些 渠道合作商會對你的 App 做詳細的要求,只有達到相應的要求後才允許你的 App 預裝到手機上。而且,越大的 App 其單價成本也會越高。所以,瘦身也是我們專案做大之後一定會遇到的一個問題。
體積過大對 App 效能的影響此外,包體積除了會影響 應用的下載轉化率 之外,主要還會對 App 三個方面 的效能有一定的影響,如下所示:
1)、安裝時間:比如 檔案拷貝、Library 解壓,並且,在編譯 ODEX 的時候,特別是對於 Android 5.0 和 6.0 系統來說,耗費的時間比較久,而 Android 7.0 之後有了 混合編譯,所以還可以接受。最後,App 變大後,其 簽名校驗 的時間也會變長。2)、執行時記憶體:Resource 資源、Library 以及 Dex 類載入都會佔用應用的一部分記憶體。3)、ROM 空間:如果應用的安裝包大小為 50MB,那麼啟動解壓之後很可能就已經超過 100MB了。並且,如果 快閃記憶體空間不足,很可能出現“寫入放大”的情況,它是快閃記憶體和固態硬碟(SSD)中一種不良的現象,快閃記憶體在可重新寫入資料前必須先擦除,而擦除操作的粒度與寫入操作相比低得多,執行這些操作就會多次移動(或改寫)使用者資料和元資料。因此,要改寫資料,就需要讀取快閃記憶體某些已使用的部分,更新它們,並寫入到新的位置,如果新位置在之前已被使用過,還需連同先擦除;由於快閃記憶體的這種工作方式,必須擦除改寫的快閃記憶體部分比新資料實際需要的大得多。即最終可能導致實際寫入的物理資料量是寫入資料量的多倍。2、APK 組成我們都知道,Android 專案最終會編譯成一個 .apk 字尾的檔案,實際上它就是一個 壓縮包。因此,它內部還有很多不同型別的檔案,這些檔案,按照大小,共分為如下四類:
1)、程式碼相關:classes.dex,我們在專案中所編寫的 java 檔案,經過編譯之後會生成一個 .class檔案,而這些所有的 .class 檔案呢,它最終會經過 dx 工具編譯生成一個 classes.dex。2)、資源相關:res、assets、編譯後的二進位制資原始檔 resources.arsc 和 清單檔案 等等。res 和 assets 的不同在於 res 目錄下的檔案會在 .R 檔案中生成對應的資源 ID,而 assets 不會自動生成對應的 ID,而是通過 AssetManager 類的介面來獲取。此外,每當在 res 資料夾下放一個檔案時,aapt 就會自動生成對應的 id 並儲存在 .R 檔案中,但 .R 檔案僅僅只是保證編譯程式不會報錯,實際上在應用執行時,系統會根據 ID 尋找對應的資源路徑,而 resources.arsc 檔案就是用來記錄這些 ID 和 資原始檔位置對應關係 的檔案。3)、So 相關:lib 目錄下的檔案,這塊檔案的優化空間其實非常大。此外,還有 META-INF,它存放了應用的 簽名信息,其中主要有 3個檔案,如下所示:
1)、MANIFEST.MF:其中每一個資原始檔都有一個對應的 SHA-256-Digest(SHA1) 簽名,MANIFEST.MF 檔案的 SHA256(SHA1) 經過 base64 編碼的結果即為 CERT.SF 中的 SHA256(SHA1)-Digest-Manifest 值。2)、CERT.SF:除了開頭處定義的 SHA256(SHA1)-Digest-Manifest 值,後面幾項的值是對 MANIFEST.MF 檔案中的每項再次 SHA256(SHA1) 經過 base64 編碼後的值。3)、CERT.RSA:其中包含了公鑰、加密演算法等資訊。首先,對前一步生成的 CERT.SF 使用了 SHA256(SHA1)生成了數字摘要並使用了 RSA 加密,接著,利用了開發者私鑰進行簽名。然後,在安裝時使用公鑰解密。最後,將其與未加密的摘要資訊(MANIFEST.MF檔案)進行對比,如果相符,則表明內容沒有被修改。3、APK分析下面,我們就來學習 APK 分析的 四種常用方式。
1、使用 ApkTool 反編譯工具分析 APK第一種方式,就是使用 ApkTool 這個反編譯工具,它的官網地址如下:
其具體的 反編譯命令 如下所示:
apktool d xxx.apk
下面,我們就來使用 ApkTool 來對應用進行反編譯。
ApkTool反編譯實戰1、下載並配置apktoolapktool 下載配置官方文件
1)、下載指令碼,儲存為 apktool 檔案。2)、下載最新版 apktool.jar(需要翻牆)3)、將下載的 jar 包重新命名為 apktool.jar。4)、配置環境變數,這裡有兩種方案,如下所示:第一種是直接將 apktool 和 apktool.jar 移到 /usr/local/bin 目錄,但是這裡需要 root 許可權,命令前加 sudo,回車後輸入密碼即可。第二種是在 ~/.bash_profile 檔案下配置,首先新建 apktool 資料夾,將兩個檔案放到這個檔案下,開啟終端,使用 vim 加上環境配置,其命令如下所示: // 1、使用vim命令在命令列開啟.bash_profile檔案,並可以在命令列 // 上編輯,當然,你也可以直接開啟.bash_profile檔案 vim ~/.bash_profile // 2、在.bash_profile最後加上這一行即可 export PATH=前面路徑/apktool:$PATH // 3、使編輯後的配置生效 source ~/.bash_profile
5)、最後,使用以下命令將兩個檔案許可權設定為 可執行 即可:sudo chmod a+x file
2、使用ApkTool分析APK
我們在命令列下輸入以下命令對 APK 進行反編譯,如下所示:
java -jar apktool_2.3.4.jar apktool d app-release.apk
反編譯完成之後,它就會在當前的資料夾下面生成 app-release 的目錄,目錄結構如下所示:
這樣我們就可以看到當前 App的具體組成 了。下面,我們介紹下第二種 APK 分析 的方式。
2、使用AS 2.2之後提供的Analyze APKAnalyze APK 具有如下功能:
1)、可以直觀地檢視到 APK 的組成,比如大小、佔比等等。2)、檢視 dex 檔案的組成。3)、對不同的 APK 進行對比分析。下面,我們就來具體實戰一下,需要注意的是,我們可以 直接將電腦上的 apk 拖進 AS 中就可以自動使用 Analyze APK 開啟 apk。然後,我們就可以看到 APK 檔案的絕對大小以及各組成檔案的百分佔比,如下圖所示:
可以看到,Awesome-WanAndroid 應用的 classes.dex 的大小為 3.3MB,總佔比為 42.2%。並且,lib和 res 目錄也有 1.9MB,總佔比大概為 25%,因此,對於 Awesome-WanAndroid App的優化方向就應該是 dex 為主、so 和 res 為輔 了。此外,我們還可以檢視 classes.dex 中還包含有哪些類,如下圖所示:
我們平時在做 競品分析 的時候,就能夠很方便地來 看一下我們 App 的競品用到了哪些第三方 SDK。同時,我們也可以從清單檔案中很方便地檢視 APK 檔案的最終版本,因為 Analyze APK 能夠直接對清單檔案進行解析。
此外,在應用右上角還有一個 Compare with previos APK 的按鈕,我們點選它之後,就可以 將當前的 APK 與別的版本的 APK 進行對比,這樣就可以對新舊兩個版本的 APK 檔案大小進行對比。
接下來,我們再介紹下第三種 APK 分析的方式。
3、使用 nimbledroid 進行 APK 效能分析nimbledroid官網
nibledroid 是美國哥倫比亞大學的博士創業團隊研發出來的分析 Android App 效能指標的系統,分析的方式有靜態和動態兩種方式,如下所示:
1)、靜態分析:可以分析出APK安裝包中大檔案排行榜,Dex 方法數和知名第三方 SDK 的方法數及佔程式碼整體的比例。2)、動態分析:可以給出 冷啟動時間, 列出 Block UI 的具體方法, 記憶體佔用, 以及 Hot Methods, 從這些分析報告中, 可以 定位出具體的優化點。它的使用方式其實非常簡單,只需要直接上傳APK 即可。然後,nimbledroid 網站的後臺就會自動對 APK 進行分析,並最終給出一份 全面的 APK 分析報告。
下面,我們再來介紹最後一種 APK 分析工具,即二進位制檢查工具 android-classshark。
4、使用 android-classshark 進行 APK 分析android-classshark專案地址
android-classshark 是一個 面向 Android 開發人員的獨立二進位制檢查工具,它可以 瀏覽任何的 Android 可執行檔案,並且檢查出資訊,比如類的介面、成員變數等等,此外,它還可以支援多種格式,比如說 APK、Jar、Class、So 以及所有的 Android 二進位制檔案如清單檔案等等。下面,我們就來使用 android-classshark 來進行一下實戰。
android-classshark 實戰首先,我們從它的 Github 地址上下載對應的 ClassyShark.jar,地址如下所示:
ClassyShark.jar-下載地址
然後,我們雙擊開啟 ClassShark.jar,拖動我們的 APK 到它的工作空間即可。接下來,我們就可以看到 Apk 的分析介面了,這裡我們點選 classes 下的 classes.dex,在分析介面 左邊 可以看到該 dex 的方法數和檔案大小,並且,最下面還顯示出了該 dex 中包含有 Native Call 的類。如下圖所示:
此外,我們點選左上角的 Methods count 還可以切換到 方法數環形圖示統計介面,我們不僅可以 直觀地看到各個包下的方法數和相對大小,還可以看到各個子包下的方法數和相對大小。如下圖所示:
小結本篇主要闡述了APK瘦身優勢與分析,下一篇將深入探究程式碼瘦身方案。
相信它會給大家帶來很多收穫: