[TOC]
參見官方文檔:[https://developer.android.com/topic/performance/reduce-apk-size?hl=zh-cn](https://developer.android.com/topic/performance/reduce-apk-size?hl=zh-cn)
## 了解APK結(jié)構(gòu)

## 縮減APK大小
使用App Bundle上傳應(yīng)用不適用于國(guó)內(nèi)環(huán)境,暫不介紹。App Bundle 針對(duì)不同用戶的設(shè)備配置,提供經(jīng)過優(yōu)化的 APK,只需下載運(yùn)行應(yīng)用時(shí)所需的代碼和資源,無需再編譯、簽署和管理多個(gè) APK 以支持不同的設(shè)備。可以使用Android Size Analyzer插件或者命令行對(duì)項(xiàng)目進(jìn)行分析,以確定哪些文件可以進(jìn)行動(dòng)態(tài)分發(fā)。
針對(duì)于國(guó)內(nèi)的生態(tài)環(huán)境,我們主要從以下幾個(gè)方面進(jìn)行APK大小的優(yōu)化:
### 縮減資源數(shù)量和大小
#### 1、移除不使用的資源文件
項(xiàng)目迭代過程中UI不斷優(yōu)化,部分資源文件不再使用,但仍存在于項(xiàng)目并被打包到APK中??梢允褂胉lint`工具來檢測(cè)未被引用的資源文件。
>`lint`工具不會(huì)掃描`assets/`文件夾、通過反射引用的資源或已鏈接至應(yīng)用的庫(kù)文件。此外,它也不會(huì)移除資源,只會(huì)提醒您它們的存在。
同時(shí),可以在應(yīng)用的`build.gradle`文件中啟用[`shrinkResources`](https://developer.android.com/studio/build/shrink-code?hl=zh-cn#shrink-resources),Gradle 會(huì)自動(dòng)為我們移除資源。
```plain
android {
// Other settings
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
```
#### 2、減少封裝庫(kù)中的資源使用量
#### 3、僅支持特定屏幕密度
目前市場(chǎng)上手機(jī)屏幕分辯率以1080P為主流,推薦應(yīng)用包含一個(gè)`xxhdpi`圖片變體即可,低密度的`ldpi`、`mdpi`、`hdpi`等可以考慮移除,Android 會(huì)自動(dòng)縮放最初為其他屏幕密度設(shè)計(jì)的現(xiàn)有資源。
#### 4、使用可繪制對(duì)象
對(duì)于可以使用Drawable對(duì)象動(dòng)態(tài)繪制的圖片,如背景圖等,推薦使用Drawable對(duì)象替代,其占用的空間會(huì)比靜態(tài)圖片資源小。
#### 5、重復(fù)使用資源
對(duì)于一些可以重復(fù)使用的圖片資源,推薦替換色調(diào)調(diào)整、陰影設(shè)置、旋轉(zhuǎn)等,重復(fù)使用。以下示例展示了通過繞圖片中心位置旋轉(zhuǎn) 180 度,將“拇指向上”變?yōu)椤澳粗赶蛳隆保海?```xml
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_thumb_up"
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="180" />
```
#### 6、壓縮PNG文件
`aapt`工具可以在編譯過程中通過無損壓縮來優(yōu)化放置在`res/drawable/`中的圖片資源。例如,`aapt`工具可以通過調(diào)色板將不需要超過 256 種顏色的真彩色 PNG 轉(zhuǎn)換為 8 位 PNG。這樣做會(huì)生成質(zhì)量相同但內(nèi)存占用量更小的圖片。
使用注意:
* `aapt`工具不會(huì)縮減`asset/`文件夾中包含的 PNG 文件。
* 圖片文件需要使用 256 種或更少的顏色才可供`aapt`工具進(jìn)行優(yōu)化。
* `aapt`工具可能會(huì)擴(kuò)充已壓縮的 PNG 文件。為防止出現(xiàn)這種情況,您可以在 Gradle 中使用`cruncherEnabled`標(biāo)記為 PNG 文件停用此過程:
```plain
aaptOptions {
cruncherEnabled = false
}
```
#### 7、壓縮PNG和JPEG文件
可以使用[pngcrush](http://pmt.sourceforge.net/pngcrush/)、[pngquant](https://pngquant.org/)或[zopflipng](https://github.com/google/zopfli)等工具縮減 PNG 文件的大小,同時(shí)不損失畫質(zhì)。所有這些工具都可以縮減 PNG 文件的大小,同時(shí)保持肉眼感知的畫質(zhì)不變。
`pngcrush`工具尤為有效:該工具會(huì)迭代 PNG 過濾器和 zlib (Deflate) 參數(shù),使用過濾器和參數(shù)的每個(gè)組合來壓縮圖片。然后,它會(huì)選擇可產(chǎn)生最小壓縮輸出的配置。
要壓縮 JPEG 文件,可以使用[packJPG](http://www.elektronik.htw-aalen.de/packjpg/)和[guetzli](https://github.com/google/guetzli)等工具。
#### 8、使用 WebP 文件格式
使用[WebP](https://developers.google.com/speed/webp/?hl=zh-cn)文件格式的圖片(而不是使用 PNG 或 JPEG 文件)。Android Studio提供了轉(zhuǎn)換單張圖片或整個(gè)目錄為WebP格式的方法,具體可參考[https://developer.android.com/studio/write/convert-webp?hl=zh-cn](https://developer.android.com/studio/write/convert-webp?hl=zh-cn)
#### 9、使用矢量圖形
可以使用矢量圖形創(chuàng)建與分辨率無關(guān)的圖標(biāo)和其他可伸縮媒體。
#### 10、將矢量圖形用于動(dòng)畫圖片
請(qǐng)勿使用`[AnimationDrawable](https://developer.android.com/reference/android/graphics/drawable/AnimationDrawable?hl=zh-cn)`創(chuàng)建逐幀動(dòng)畫,這樣做需要為動(dòng)畫的每個(gè)幀添加單獨(dú)的位圖文件,而這會(huì)大大增加 APK 的大小。
應(yīng)改為使用[`AnimatedVectorDrawableCompat`](https://developer.android.com/reference/androidx/vectordrawable/graphics/drawable/AnimatedVectorDrawableCompat?hl=zh-cn)創(chuàng)建[動(dòng)畫矢量可繪制資源](https://developer.android.com/training/material/animations?hl=zh-cn#AnimVector)。
### 減少原生和Java代碼
#### 1、移除不必要的生成代碼
確保了解自動(dòng)生成的任何代碼所占用的空間。例如,許多協(xié)議緩沖區(qū)工具會(huì)生成過多的方法和類,這可能會(huì)使應(yīng)用的大小增加一倍或兩倍。
#### 2、避免使用枚舉
單個(gè)枚舉會(huì)使應(yīng)用的`classes.dex`文件增加大約 1.0 到 1.4KB 的大小。這些增加的大小會(huì)快速累積,產(chǎn)生復(fù)雜的系統(tǒng)或共享庫(kù)。如果可能,請(qǐng)考慮使用`@IntDef`注釋和[代碼縮減](https://developer.android.com/studio/build/shrink-code?hl=zh-cn)移除枚舉并將它們轉(zhuǎn)換為整數(shù)。此類型轉(zhuǎn)換可保留枚舉的各種安全優(yōu)勢(shì)。
#### 3、縮減原生二進(jìn)制文件的大小
如果您的應(yīng)用使用原生代碼和 Android NDK,還可以通過優(yōu)化代碼來縮減發(fā)布版應(yīng)用的大小。移除調(diào)試符號(hào)和不提取原生庫(kù)是兩項(xiàng)很實(shí)用的技術(shù)。
### 總結(jié)
綜上可見,縮減APK大小主要從縮減資源文件和縮減原生及Java代碼兩方面入手,著重關(guān)注以下幾點(diǎn):
* 移除未使用的資源文件
* 使用可繪制對(duì)象
* 壓縮圖片文件,優(yōu)先使用WebP格式文件
* 避免使用枚舉
* 僅打包有需要平臺(tái)的so文件
- 導(dǎo)讀
- Java知識(shí)
- Java基本程序設(shè)計(jì)結(jié)構(gòu)
- 【基礎(chǔ)知識(shí)】Java基礎(chǔ)
- 【源碼分析】Okio
- 【源碼分析】深入理解i++和++i
- 【專題分析】JVM與GC
- 【面試清單】Java基本程序設(shè)計(jì)結(jié)構(gòu)
- 對(duì)象與類
- 【基礎(chǔ)知識(shí)】對(duì)象與類
- 【專題分析】Java類加載過程
- 【面試清單】對(duì)象與類
- 泛型
- 【基礎(chǔ)知識(shí)】泛型
- 【面試清單】泛型
- 集合
- 【基礎(chǔ)知識(shí)】集合
- 【源碼分析】SparseArray
- 【面試清單】集合
- 多線程
- 【基礎(chǔ)知識(shí)】多線程
- 【源碼分析】ThreadPoolExecutor源碼分析
- 【專題分析】volatile關(guān)鍵字
- 【面試清單】多線程
- Java新特性
- 【專題分析】Lambda表達(dá)式
- 【專題分析】注解
- 【面試清單】Java新特性
- Effective Java筆記
- Android知識(shí)
- Activity
- 【基礎(chǔ)知識(shí)】Activity
- 【專題分析】運(yùn)行時(shí)權(quán)限
- 【專題分析】使用Intent打開三方應(yīng)用
- 【源碼分析】Activity的工作過程
- 【面試清單】Activity
- 架構(gòu)組件
- 【專題分析】MVC、MVP與MVVM
- 【專題分析】數(shù)據(jù)綁定
- 【面試清單】架構(gòu)組件
- 界面
- 【專題分析】自定義View
- 【專題分析】ImageView的ScaleType屬性
- 【專題分析】ConstraintLayout 使用
- 【專題分析】搞懂點(diǎn)九圖
- 【專題分析】Adapter
- 【源碼分析】LayoutInflater
- 【源碼分析】ViewStub
- 【源碼分析】View三大流程
- 【源碼分析】觸摸事件分發(fā)機(jī)制
- 【源碼分析】按鍵事件分發(fā)機(jī)制
- 【源碼分析】Android窗口機(jī)制
- 【面試清單】界面
- 動(dòng)畫和過渡
- 【基礎(chǔ)知識(shí)】動(dòng)畫和過渡
- 【面試清單】動(dòng)畫和過渡
- 圖片和圖形
- 【專題分析】圖片加載
- 【面試清單】圖片和圖形
- 后臺(tái)任務(wù)
- 應(yīng)用數(shù)據(jù)和文件
- 基于網(wǎng)絡(luò)的內(nèi)容
- 多線程與多進(jìn)程
- 【基礎(chǔ)知識(shí)】多線程與多進(jìn)程
- 【源碼分析】Handler
- 【源碼分析】AsyncTask
- 【專題分析】Service
- 【源碼分析】Parcelable
- 【專題分析】Binder
- 【源碼分析】Messenger
- 【面試清單】多線程與多進(jìn)程
- 應(yīng)用優(yōu)化
- 【專題分析】布局優(yōu)化
- 【專題分析】繪制優(yōu)化
- 【專題分析】?jī)?nèi)存優(yōu)化
- 【專題分析】啟動(dòng)優(yōu)化
- 【專題分析】電池優(yōu)化
- 【專題分析】包大小優(yōu)化
- 【面試清單】應(yīng)用優(yōu)化
- Android新特性
- 【專題分析】狀態(tài)欄、ActionBar和導(dǎo)航欄
- 【專題分析】應(yīng)用圖標(biāo)、通知欄適配
- 【專題分析】Android新版本重要變更
- 【專題分析】唯一標(biāo)識(shí)符的最佳做法
- 開源庫(kù)源碼分析
- 【源碼分析】BaseRecyclerViewAdapterHelper
- 【源碼分析】ButterKnife
- 【源碼分析】Dagger2
- 【源碼分析】EventBus3(一)
- 【源碼分析】EventBus3(二)
- 【源碼分析】Glide
- 【源碼分析】OkHttp
- 【源碼分析】Retrofit
- 其他知識(shí)
- Flutter
- 原生開發(fā)與跨平臺(tái)開發(fā)
- 整體歸納
- 狀態(tài)及狀態(tài)管理
- 零碎知識(shí)點(diǎn)
- 添加Flutter到現(xiàn)有應(yīng)用
- Git知識(shí)
- Git命令
- .gitignore文件
- 設(shè)計(jì)模式
- 創(chuàng)建型模式
- 結(jié)構(gòu)型模式
- 行為型模式
- RxJava
- 基礎(chǔ)
- Linux知識(shí)
- 環(huán)境變量
- Linux命令
- ADB命令
- 算法
- 常見數(shù)據(jù)結(jié)構(gòu)及實(shí)現(xiàn)
- 數(shù)組
- 排序算法
- 鏈表
- 二叉樹
- 棧和隊(duì)列
- 算法時(shí)間復(fù)雜度
- 常見算法思想
- 其他技術(shù)
- 正則表達(dá)式
- 編碼格式
- HTTP與HTTPS
- 【面試清單】其他知識(shí)
- 開發(fā)歸納
- Android零碎問題
- 其他零碎問題
- 開發(fā)思路
