[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结构
![](https://img.kancloud.cn/97/65/9765ec02f7c6bef887f2c7cd1f583dac_951x609.png)
## 缩减APK大小
使用App Bundle上传应用不适用于国内环境,暂不介绍。App Bundle 针对不同用户的设备配置,提供经过优化的 APK,只需下载运行应用时所需的代码和资源,无需再编译、签署和管理多个 APK 以支持不同的设备。可以使用Android Size Analyzer插件或者命令行对项目进行分析,以确定哪些文件可以进行动态分发。
针对于国内的生态环境,我们主要从以下几个方面进行APK大小的优化:
### 缩减资源数量和大小
#### 1、移除不使用的资源文件
项目迭代过程中UI不断优化,部分资源文件不再使用,但仍存在于项目并被打包到APK中。可以使用`lint`工具来检测未被引用的资源文件。
>`lint`工具不会扫描`assets/`文件夹、通过反射引用的资源或已链接至应用的库文件。此外,它也不会移除资源,只会提醒您它们的存在。
同时,可以在应用的`build.gradle`文件中启用[`shrinkResources`](https://developer.android.com/studio/build/shrink-code?hl=zh-cn#shrink-resources),Gradle 会自动为我们移除资源。
```plain
android {
// Other settings
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
```
#### 2、减少封装库中的资源使用量
#### 3、仅支持特定屏幕密度
目前市场上手机屏幕分辩率以1080P为主流,推荐应用包含一个`xxhdpi`图片变体即可,低密度的`ldpi`、`mdpi`、`hdpi`等可以考虑移除,Android 会自动缩放最初为其他屏幕密度设计的现有资源。
#### 4、使用可绘制对象
对于可以使用Drawable对象动态绘制的图片,如背景图等,推荐使用Drawable对象替代,其占用的空间会比静态图片资源小。
#### 5、重复使用资源
对于一些可以重复使用的图片资源,推荐替换色调调整、阴影设置、旋转等,重复使用。以下示例展示了通过绕图片中心位置旋转 180 度,将“拇指向上”变为“拇指向下”::
```xml
android:drawable="@drawable/ic_thumb_up"
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="180" />
```
#### 6、压缩PNG文件
`aapt`工具可以在编译过程中通过无损压缩来优化放置在`res/drawable/`中的图片资源。例如,`aapt`工具可以通过调色板将不需要超过 256 种颜色的真彩色 PNG 转换为 8 位 PNG。这样做会生成质量相同但内存占用量更小的图片。
使用注意:
* `aapt`工具不会缩减`asset/`文件夹中包含的 PNG 文件。
* 图片文件需要使用 256 种或更少的颜色才可供`aapt`工具进行优化。
* `aapt`工具可能会扩充已压缩的 PNG 文件。为防止出现这种情况,您可以在 Gradle 中使用`cruncherEnabled`标记为 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 文件的大小,同时不损失画质。所有这些工具都可以缩减 PNG 文件的大小,同时保持肉眼感知的画质不变。
`pngcrush`工具尤为有效:该工具会迭代 PNG 过滤器和 zlib (Deflate) 参数,使用过滤器和参数的每个组合来压缩图片。然后,它会选择可产生最小压缩输出的配置。
要压缩 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提供了转换单张图片或整个目录为WebP格式的方法,具体可参考[https://developer.android.com/studio/write/convert-webp?hl=zh-cn](https://developer.android.com/studio/write/convert-webp?hl=zh-cn)
#### 9、使用矢量图形
可以使用矢量图形创建与分辨率无关的图标和其他可伸缩媒体。
#### 10、将矢量图形用于动画图片
请勿使用`[AnimationDrawable](https://developer.android.com/reference/android/graphics/drawable/AnimationDrawable?hl=zh-cn)`创建逐帧动画,这样做需要为动画的每个帧添加单独的位图文件,而这会大大增加 APK 的大小。
应改为使用[`AnimatedVectorDrawableCompat`](https://developer.android.com/reference/androidx/vectordrawable/graphics/drawable/AnimatedVectorDrawableCompat?hl=zh-cn)创建[动画矢量可绘制资源](https://developer.android.com/training/material/animations?hl=zh-cn#AnimVector)。
### 减少原生和Java代码
#### 1、移除不必要的生成代码
确保了解自动生成的任何代码所占用的空间。例如,许多协议缓冲区工具会生成过多的方法和类,这可能会使应用的大小增加一倍或两倍。
#### 2、避免使用枚举
单个枚举会使应用的`classes.dex`文件增加大约 1.0 到 1.4KB 的大小。这些增加的大小会快速累积,产生复杂的系统或共享库。如果可能,请考虑使用`@IntDef`注释和[代码缩减](https://developer.android.com/studio/build/shrink-code?hl=zh-cn)移除枚举并将它们转换为整数。此类型转换可保留枚举的各种安全优势。
#### 3、缩减原生二进制文件的大小
如果您的应用使用原生代码和 Android NDK,还可以通过优化代码来缩减发布版应用的大小。移除调试符号和不提取原生库是两项很实用的技术。
### 总结
综上可见,缩减APK大小主要从缩减资源文件和缩减原生及Java代码两方面入手,着重关注以下几点:
* 移除未使用的资源文件
* 使用可绘制对象
* 压缩图片文件,优先使用WebP格式文件
* 避免使用枚举
* 仅打包有需要平台的so文件