隨着業務複雜度的逐漸增長,代碼、資源也在不斷的增長,此時你的APP大小也在增長。從用戶層面來講,面對動輒幾十兆的APP來講在非WIFI狀況下仍是會猶豫要不要下載,不下載你就可能所以失去了一個用戶。從公司層面來說,流量就是錢,減小APP的大小就顯得尤其重要。從開發者層面上來說,你掌握了這個手藝也會略顯逼格滿滿。javascript
廢話很少說了,開始正題。php
知己知彼,方能百戰不殆。瞭解應用程序APK的結構對於咱們來講頗有幫助。APK文件由一個ZIP存檔組成,其中包含組成應用程序的全部文件。這些文件包括Java類文件,資源文件和包含編譯資源的文件。java
APK包含如下目錄:android
通常來說APK結構中比較大的部分通常是classes.dex、lib、res、assets這些文件或者目錄。因此接下來將會針對這四種狀況進行講解。安全
另外,咱們經過APK Analyser 能夠分析 APK;性能優化
classes.dex 包含了全部 Java 代碼。當你編譯你的應用時,gradle 會將你的全部模塊裏的 .class 文件轉換成 .dex 文件並將這些文件合成一個 classes.dex 文件。bash
單個的 classes.dex 文件能夠容納大約 64K 方法。若是你達到了這個限制,你必需要在你的工程中啓用 multidexing。這將會建立另外一個 classes1.dex 文件去存儲剩下的方法。因此 classes.dex 文件數目由你的方法數而定。網絡
隨着業務的頻繁變動以及複雜度的增長,咱們每每會使用第三方Libaray,有時候咱們可能僅僅用到了不多一部分的功能,這個時候就須要慎重考慮徹底引用。從個人開發經驗上來說,寧願參照本身去實現,也不肯意多引入一個第三方庫。架構
一個枚舉能夠爲您的應用程序的classes.dex文件添加大約1.0到1.4 KB的大小 。這些添加能夠快速累積到複雜系統或共享庫。若是可能,請考慮使用@IntDef註釋,這種類型轉換保留了枚舉的全部類型安全優點。app
下面這段來自 build.gradle 文件的代碼用於爲發佈構建啓用代碼壓縮:
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-android-optimize.txt 文件。它包括相同的 ProGuard 規則,但還包括其餘在字節碼一級(方法內和方法間)執行分析的優化,以進一步減少 APK 大小和幫助提升其運行速度。
proguard-rules.pro 文件用於添加自定義 ProGuard 規則。默認狀況下,該文件位於模塊根目錄(build.gradle 文件旁)。
題外話
res/raw和assets的相同點:
二者目錄下的文件在打包後會原封不動的保存在apk包中,不會被編譯成二進制。
res/raw和assets的不一樣點:
3.1 圖片資源優化策略
格式壓縮;使用TinyPng或者Guetzli進行壓縮。
使用WebP文件格式
定位Android 3.2(API級別13)或更高級別時 ,您也可使用WebP文件格式來製做圖像,而不是使用PNG或JPEG文件。WebP格式提供有損壓縮(如JPEG)以及透明度(如PNG),但能夠提供比JPEG或PNG更好的壓縮。
Android 4.0 (API level 14) 支持有損壓縮的WebP格式,Android 4.3 (API level 18) 開始支持無損透明WebP圖像。
看下圖:
壓縮效率極高,僅爲PNG格式的12%。驚喜不驚喜。。。
使用矢量圖形
您可使用矢量圖形來建立與分辨率無關的圖標和其餘可伸縮媒體。使用這些圖形能夠大大減小您的APK足跡。矢量圖像在Android中表示爲VectorDrawable對象。經過一個VectorDrawable對象,一個100字節的文件能夠生成一個與屏幕尺寸一致的清晰圖像。
可是,系統渲染每一個 VectorDrawable對象須要很長時間,而較大的圖像須要更長的時間才能顯示在屏幕上。所以,只有在顯示小圖像時才考慮使用這些矢量圖形。
其它策略
有時候咱們可能對一張圖片進行重複利用,好比一張圖片僅僅是總體顏色的變換可使用setColorFilter或者tint。儘可能減小使用幀動畫,那但是一堆圖片呀。
3.2 壓縮資源
要啓用資源壓縮,請在 build.gradle 文件中將 shrinkResources 屬性設置爲 true。
android {
...
buildTypes {
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
複製代碼
資源壓縮器目前不會移除 values/ 文件夾中定義的資源(例如字符串、尺寸、樣式和顏色)。這是由於 Android 資源打包工具 (AAPT) 不容許 Gradle 插件爲資源指定預約義版本。
同時,咱們也能夠指定哪些資源能夠保留下來。
例如,將下邊的代碼保存在 res/raw/keep.xml。構建不會將該文件打包到 APK 之中。
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*" tools:discard="@layout/unused2" />
複製代碼
resources有如下屬性:
safe和strict的優化策略:
safe能夠簡單理解爲安全模式,它會盡最大努力檢查代碼中可能會使用到的資源進行保留,避免運行時錯誤。
若是你的代碼調用 Resources.getIdentifier(),這就表示你的代碼將根據動態生成的字符串查詢資源名稱。當你執行這一調用時,默認狀況下資源壓縮器會採起防護性行爲,將全部具備匹配名稱格式的資源標記爲可能已使用,沒法移除。
String name = String.format("img_%1d", angle + 1);
res = getResources().getIdentifier(name, "drawable", getPackageName());
複製代碼
img_ 前綴的資源標記爲已使用。
在strict模式下,img_前綴的資源會作未使用的處理,所以你須要使用tools:keep手動進行已使用標識。
移除未使用的備用資源
咱們知道google給咱們的apk提供了國際化支持,如適應不一樣的屏幕分辨率的drawable資源,還有適應不一樣語言的字符串資源等等,可是在不少狀況下咱們只須要一些指定分辨率和語言的資源就能夠了,這個時候咱們可使用resConfigs方法來配置。
defaultConfig {
// 對於國際化支持只打包中文資源,
resConfigs "zh-rCN"
}
複製代碼
這裏咱們主要講一下lib中動態連接庫的優化策略,也就是SO文件。若是你有NDK的開發經驗可能會更容易理解一些。
爲了支持不一樣指令集的狀況,應用可能會包含armeabi、armeabi-v7a、x86的SO文件等。
目前主流的機型都是支持armeabi-v7a的,而且armeabi-v7a兼容armeabi。因此在通常的開發中咱們只須要使用armeabi-v7a 進行ABI支持。
有些SO庫能夠採用網絡下載,把負擔放到用戶安裝完應用以後。對於哪些SO文件能夠放到網絡中加載,還須要看具體業務狀況。
題外話,若是運行時找不到SO的話,會致使應用崩潰。
java.lang.UnsatisfiedLinkError: Couldn't load stlport_shared
from loader dalvik.system.PathClassLoader: findLibrary returned null
at java.lang.Runtime.loadLibrary(Runtime.java:365)
at java.lang.System.loadLibrary(System.java:535)
at com.your.app.NativeClass.<clinit>(Native.java:16)
... 63 more
Caused by: java.lang.UnsatisfiedLinkError: Library stlport_shared not found
at java.lang.Runtime.loadLibrary(Runtime.java:461)
at java.lang.System.loadLibrary(System.java:557)
at com.your.app.NativeClass.<clinit>(Native.java:16)
... 5 more
複製代碼
不過也是有辦法應對的,能夠參見這個開源項目;ReLinker
5.1.全方位性能調優技術體系;
5.2.Android架構師腦圖;
5.3.全套高級架構視頻;
正在整理一套完整的Android架構視頻,免費分享。目前還在更新中,歡迎關注謝謝支持
(包括java基礎與原理,自定義控件、NDK、架構設計、混合式開發(Flutter,Weex)、性能優化、完整商業項目開發等技術體系)