为什么要优化安装包大小
提高应用的下载转化率和留存率。
1.用户可能会因为应用大小而放弃下载应用。
2.由于手机内存问题可能会导致用户卸载占用空间较大的应用。
除了下载下载转化率和留存率, 安装包体积优化还有一些理由:
一、应用安装包构成分析
1.assets文件夹:存放一些配置文件、资源文件,assets不会自动生成对应的 ID,而是通过 AssetManager 类的接口获取。
2.META-INF文件夹:包含CERT.SF和CERT.RSA签名文件以及MANIFEST.MF 清单文件。保存应用的签名信息,签名信息可以验证 APK 文件的完整性。
3.res文件夹:没有被编译进resources.arsc
文件的资源: layout, drawable等。这个目录存放资源文件,会自动生成对应的 ID 并映射到 .R 文件中,访问直接使用资源 ID。
4.resources.arsc:记录着资源文件和资源 ID 之间的映射关系,用来根据资源 ID 寻找资源。编译后的二进制资源文件, 包含了所有res/values
中的XML内容, 如字符串, style等, 也包括对没编译进来的资源(比如layout和图片)的路径.
5.AndroidManifest.xml:这个文件用来描述 Android 应用的配置信息,一些组件的注册信息、可使用权限等。
6.classes.dex:Dalvik 字节码程序,让 Dalvik 虚拟机可执行,一般情况下,Android 应用在打包时通过 Android SDK 中的 dx 工具将 Java 字节码转换为 Dalvik 字节码。包含以Dalvik / ART虚拟机可理解的DEX文件格式编译的类。
7.lib:包含特定于处理器软件层的编译代码。该目录包含了每种平台的子目录,像armeabi,armeabi-v7a, arm64-v8a,x86,x86_64,和mips。
lib、class.dex和res占用了超过90%的空间,所以这三块是优化Apk大小的重点(实际情况不唯一)
二、常用方案
1.设备屏幕支持
当一个屏幕密度下没有提供特定的资源, Android会自动根据这个资源其他密度的版本进行缩放
我们通常会放置多套不同分辨率的图片以适配不同的屏幕,这里可以进行适当的删减。在实际使用中,只保留一到两套就足够了(保留一套的话建议保留xxhdpi,两套的话就加上hdpi).
2.压缩图文文件
可以用一些工具对PNG和JPEG图片进行无损压缩: 图片质量无损但是尺寸变小.
3.使用WebP格式的图片
可以使用WebP格式的图片, 比JPEG和PNG压缩得更好.
Android Studio提供了转换工具: Create WebP images
注意: Google Play只接受PNG作为launcher icon.
4.shape的使用
很多时候我们并不需要一个图片, 比如纯色或渐变色的背景, 带边框, 带圆角等.
用
尺寸就会比较小, 也不用多个密度的版本.
5.复用资源
这里的复用可以是改变了颜色和旋转方向等的复用.
比如改资源的tint, 或者把一个图旋转了之后再用. (thumb up变成thumb down了).
6.使用矢量图
可以使用矢量图来作为可伸缩的资源, 在Android中是VectorDrawable对象.
但是矢量图的渲染需要系统的时间花销, 所以推荐只有小的icon使用矢量图.
7.逐帧动画
不要再使用很多个图片逐帧播放来实现一个动画效果了.
尽量用改变属性的动画来节省资源使用.
另外还有一些手段比如在程序中绘制, 而不是使用图片.
8.Lint静态分析
针对不用的资源, 可以专门这样检查:
在Android Studio中: Analyze -> Run Inspection by Name... -> Unused Resources
扫描后会对所有未使用的资源给出警告.
注意, 因为是Lint静态检查, 所以会有一些错报和漏报的情况:
assets/
目录不被扫描.getIdntifer()
方法, 拼名字使用, 会被lint错误地报告说没有用到.静态检查只是帮我们检测并报告, 真正要移除这些资源还得靠我们手动删除.
lintOptions {
abortOnError false
}
9.代码压缩和混淆
ProGuard -> R8会帮我们删除不用的代码, 进行名称改写和代码优化.
minifyEnabled true
不用的代码被移除了, 类和成员的名称都被改得很短, 从而有效地减小了dex文件的大小.
这里需要注意rules的编写, 不要过度保护.
比较追求极致的方法会从这个方面下手, 进一步细化优化ProGuard Rules, 以达到更深度的混淆和压缩.
10.减少lib文件大小,精简支持的cpu架构:
由于引用了很多第三方库,lib文件夹占用的空间通常都很大,特别是有so库的情况下。很多so库会同时引入armeabi、armeabi-v7a和x86这几种类型,这里可以只保留armeabi或armeabi-v7a的其中一个就可以了,实际上微信等主流app都是这么做的。
只需在build.gradle直接配置即可,NDK配置同理
defaultConfig {
ndk {
abiFilters 'armeabi-v7a'
}
}
11.精简支持语言
resConfigs "en", "zh-rCN"
https://www.jianshu.com/p/a0db5e588506
https://www.cnblogs.com/cr330326/p/8011523.html
https://www.cnblogs.com/mengdd/p/reduce-size-of-android-app.html
https://www.jianshu.com/p/c76a032b0f4c