性能優化系列(七)APK 體積優化

文章首發「Android波斯灣」公衆號,更新地址:https://github.com/jeanboydev/Android-ReadTheFuckingSourceCode

減少應用程序安裝包的大小,不僅僅減少了用戶的網絡數據流量還減少了下載等待的時間。毋庸置疑,儘量減少程序安裝包的大小是十分有必要的。

通常來說,減少程序安裝包的大小有兩條規律:要麼減少程序資源的大小,要麼就是減少程序的代碼量。

APK 構成

在開始講瘦身技巧之前,先來講一下 APK 的構成。可以用 Android Studio 中的 APK Analyzer 打開 APK 查看。

在這裏插入圖片描述

可以看到 APK 由以下主要部分組成:

文件/目錄 描述
lib/ 存放 so 文件,可能會有 armeabi、armeabi-v7a、arm64-v8a、x86、x86_64、mips,大多數情況下只需要支持 armabi 與 x86 的架構即可,如果非必需,可以考慮拿掉 x86 的部分
res/ 存放編譯後的資源文件,例如:drawable、layout 等等
assets/ 應用程序的資源,應用程序可以使用 AssetManager 來檢索該資源
META-INF/ 該文件夾一般存放於已經簽名的 APK 中,它包含了 APK 中所有文件的簽名摘要等信息
classes(n).dex classes 文件是 Java Class,被 DEX 編譯後可供 Dalvik/ART 虛擬機所理解的文件格式
resources.arsc 編譯後的二進制資源文件
AndroidManifest.xml Android 的清單文件,格式爲 AXML,用於描述應用程序的名稱、版本、所需權限、註冊的四大組件

當然還會有一些其它的文件,例如上圖中的 org/src/push_version 等文件或文件夾。這些資源是 Java Resources,感興趣的可以結合編譯工作流中的 流程圖 以及 MergeJavaResourcesTransform的源碼 看看被打入 APK 包中的資源都有哪些,這裏不做過多介紹。

在充分了解了 APK 各個組成部分以及它們的作用後,我們針對自身特點進行了分析和優化。下面將從 Zip 文件格式、classes.dex、資源文件、resources.arsc 等方面來介紹下優化技巧。

優化代碼

壓縮代碼

可以通過開啓 ProGuard 來實現代碼壓縮,可以在 build.gradle 文件相應的構建類型中添加 minifyEnabled true

打開這些編譯屬性之後,程序在打包的時候就不會把沒有引用到的代碼編譯進來,以此達到減少安裝包大小的目的。

android {
  buildTypes {
    release {
      minifyEnabled true
      proguardFiles getDefaultProguardFile(‘proguard-android.txt'),
                    'proguard-rules.pro'
    }
  }
}

除了 minifyEnabled 屬性外,還有用於定義 ProGuard 規則的 proguardFiles 屬性:

  • getDefaultProguardFile(‘proguard-android.txt') 是從Android SDK tools/proguard/ 文件夾獲取默認 ProGuard 設置。
  • proguard-rules.pro 文件用於添加自定義 ProGuard 規則。默認情況下,該文件位於模塊根目錄(build.gradle 文件旁)。

減少 ENUM 的使用

詳情可以參考:Remove Enumerations,每減少一個 ENUM 可以減少大約 1.0 到 1.4 KB 的大小。

精簡類庫

部分引入到工程中的 jar 類庫可能並不是專門針對移動端 App 而設計的,他們最開始可能是運用在 PC 或者 Server 上的。使用這些類庫不僅僅額外增加了包的大小,還增加了編譯時間。

單純依靠 Proguard 可能無法完全移除那些使用不到的方法,最佳的方式是使用一些更加輕量化,專門爲Android App 設計的 jar 類庫。

精簡 so 資源

Android系 統目前支持以下七種不同的 CPU 架構:ARMv5、ARMv7(從 2010 年起)、x86(從 2011 年起)、MIPS(從 2012 年起)、ARMv8、MIPS64 和 x86_64(從 2014 年起)。

每一個 CPU 架構對應一個 ABI:armeabi、armeabi_v7a、x86、mips、arm64_v8a、mips64、x86_64。

所有的 x86、x86_64、armeabi_v7a、arm64_v8a 設備都支持 armeabi 架構的 so 文件,x86 設備能夠很好的運行 ARM 類型函數庫,但並不保證 100% 不發生 Crash,特別是對舊設備。

64 位設備(arm64-v8a、 x86_64、mips64)能夠運行 32 位的函數庫,但是以 32 位模式運行,在 64 位平臺上運行 32 位版本的 ART 和 Android 組件,將丟失專爲 64 位優化過的性能(ART、webview、media 等等)。

所以一般的應用完全可以根據自己業務需求選擇使用 armeabi 或者 armeabi_v7a 一種支持就行。

比如:微信、微博、QQ 只保留了 armeabi,Facebook、Twitter、Instagram 只保留了 armeabi_v7a。

假設只支持了 armeabi,如果有特殊要求(比如視頻應用)需要用到部分 armeabi_v7a 的 so,可以通過改名放到 armeabi 文件夾中,根據手機實際情況選擇加載。

  • 動態下發

比較大的 so 可以選擇動態下發的形式延遲加載,代碼上需要加一些判斷邏輯。

精簡語言資源

大部分應用其實並不需要支持幾十種語言的國際化支持。還好強大的gradle支持語言的配置,比如國內應用只支持中文:

android {
    defaultConfig {
        resConfigs "zh"
    }
}

安裝包拆分

設想一下,一個 low dpi,API<14 的用戶手機下載安裝的 APK 裏面卻包含了大量 xxhdpi 的資源文件,對於這個用戶來說,這個 APK 是存在很大的資源浪費的。

幸好 Android 平臺爲我們提供了拆分 APK 的方法,它能夠根據 API Level,屏幕大小以及 GPU 版本的不同進行拆分,使得對應平臺的用戶下載到最合適自己手機的安裝包。

更多關於安裝包拆分的信息,請查看 Configure APK SplitsMaintaining Multiple APKs

由於國內應用分發市場的現狀,這一條幾乎沒有辦法執行。

支持插件化

插件化技術雨後春筍一樣的都冒了出來,這些技術支持動態的加載代碼和動態的加載資源,把 APP 的一部分分離出來了,對於業務龐大的項目來說非常有用,極大的分解了 APK 大小。

因爲插件化技術需要一定的技術保障和服務端系統支持,有一定的風險,如無必要(比如一些小型項目,也沒什麼擴展業務)就不需要了,建議酌情選擇。

精簡功能業務

從統計數據分析砍掉一些沒用的功能是完全有可能的,甚至乾脆去掉一些花哨的功能出個輕聊版、極速版也不是不可以的。

比如:今日頭條極速版、QQ 輕聊版等等。

優化資源文件

移除未使用資源

確保在 build.gradle 文件中開啓了 shrinkResources 的屬性,這個屬性可以幫助移除那些在程序中使用不到的資源文件,幫助減少 App 的安裝包大小。

android {
  buildTypes {
    release {
      shrinkResources true
    }
  }
}

有選擇性的提供對應分辨率的圖片資源,系統會自動匹配最合適分辨率的圖片並執行拉伸或者壓縮的處理。

有損壓縮圖片

Android 打包本身會對 PNG 進行無損壓縮,所以使用像 Tinypng 這樣的有損壓縮是有必要的。

重點是 Tinypng 使用智能有損壓縮技術,以儘量少的失真換來圖片大小的銳減,效果非常好,強烈推薦。

使用更小的圖片

如果對於非透明的大圖,JPG 將會比 PNG 的大小有顯著的優勢,雖然不是絕對的,但是通常會減小到一半都不止。在啓動頁,活動頁等之類的大圖展示區採用 JPG 將是非常明智的選擇。

WebP 支持透明度,壓縮比比 JPG 更高但顯示效果卻不輸於 JPG,官方評測 quality 參數等於 75 均衡最佳。
相對於 JPG、PNG,WebP 作爲一種新的圖片格式,限於 Android 的支持情況暫時還沒用在手機端廣泛應用起來。從 Android 4.0+ 開始原生支持,但是不支持包含透明度,直到 Android 4.2.1+ 才支持顯示含透明度的 WebP,使用的時候要特別注意。

使用 VectorDrawable

在符合條件的情況下,使用 Vertor Drawable 替代傳統的 PNG/JPEG 圖片,能夠極大的減少圖片資源的大小。

傳統模式下,針對不同 DPI 的手機都需要提供一套 PNG/JPEG 的圖片,而如果使用 Vector Drawable 的話,只需要一個 XML 文件即可。

在這裏插入圖片描述

儘量複用已經存在的資源圖片,使用代碼的方式對已有的資源進行復用。

APK Analyzer

Android Studio 2.2 包含了 APK Analyzer,通過它我們能夠直觀地看到 APK 的組成。使用 APK Analyzer 不僅能夠減少你花在 debug 上的時間,而且還能減少你的 APK 大小。

使用 APK Analyzer,你能夠實現:

  • 查看 APK 中文件的絕對大小和相對大小。
  • 理解 dex 文件的組成。
  • 快速查看 APK 中文件的最終版本(比如AndroidManifest.xml)。
  • 對比兩個 APK。

這裏有 3 種方法訪問 APK Analyzer:

  • 拖拽 APK 到 Android Studio 的編輯窗口。
  • 切換到 Project 視圖,並且雙擊 APK 文件。
  • 在菜單欄中選擇 Build > Analyzer APK,並且選擇 APK。

更多關於 的內容可以查看 Android 開發文檔 - Analyze your build with APK Analyzer使用 APK Analyzer 分析你的 APK 這兩篇文章。

我的 GitHub

github.com/jeanboydev

技術交流羣

歡迎加入技術交流羣,來一起交流學習。

QQ 技術交流羣
微信技術交流羣

我的公衆號

歡迎關注我的公衆號,分享各種技術乾貨,各種學習資料,職業發展和行業動態。

Android 波斯灣

參考資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章