动手点关注 干货不迷路 👆
前言
目前,安卓端对于包体积的优化方案已经多如过江之鲫,我们系列的上一篇文章介绍了 Class 字节码的优化,本期我们将关注点聚焦到资源文件上,从资源二进制文件的全新角度,拓展出包体积优化的新思路。
在资源文件优化方面,通常的优化手段多集中在图片/文件压缩、资源文件名称混淆、离线下载资源文件等方面,而我们的新思路基于对于常规思路的深度分析及思考。
一开始,我们是从资源文件名称混淆入手优化,业界对于资源文件名称混淆方案,最为熟知的开源项目当属 AndResGuard,该项目优化目标为资源文件目录 res 内的文件,其优化点如下:
对重复的资源文件,以计算 md5 值的方式来判断是否重复并只保留一份;
对资源文件名称进行缩短,即名称混淆;
对 APK 中的内容采取 7zip 压缩优化;
按照此项目进行优化,总体收益可以达到非常可观的 MB 级别。但完成此项目的优化后,资源文件的进一步优化便达到瓶颈。
为了在此基础上更好的实现优化资源大小,我们需要了解资源文件目录 res 所包含的文件类型及其大小的分布情况。以抖音为例,下表是对其包含的子文件夹名称、文件数量、将文件夹 zip 压缩后大小的梳理,以文件数量降序排序:
子文件夹名称 |
文件数量 | 文件夹zip压缩后大小 |
drawable-xxhdpi-v4 | 6054 | 19.5MB |
layout | 5970 | 12.2MB |
drawable |
4388 | 4.6MB |
layout-v17 | 2985 | 8.5MB |
drawable-night-xxhdpi-v8 | 994 | ... |
drawable-xhdpi-v4 | 431 | ... |
anim | 382 | ... |
color | 152 | ... |
从上表,可以看到:
drawable-xxhdpi-v4 目录下文件数量最多有 6000+,压缩后文件大小约为 19.5MB。
drawable 目录下文件数量排第三,有 4388 个,压缩后 4.6MB,同时包含图片和.xml 文件。
文件数量排第二和第四的都是 layout 目录下的布局文件,分别有 5970,2985 个,其文件夹压缩后大小分别为 12.2MB,8.5MB。布局文件总数近 9K,文件大小约 20.7MB
可见,layout 目录下的布局文件大小已经和图片文件不相上下。而这部分如此大的文件,除了有文件名称的混淆优化之外,是否还有其他优化方式?或者其文件名称混淆是否彻底?
此外,APK 解压后的 resources.arsc 文件有 7.3MB 之大。其中包含了 app 所有资源文件名称和资源字符串值,其中是否也存在冗余字符串?
对于 layout 布局文件,从近万份之多的文件数量及 20+MB 的文件体积来看,即存在值得探究的必要。我们通过对资源文件的二进制文件格式的解析,并从文件内容被使用的角度分析,发现存在可以删除的冗余内容。在反复尝试并解决了各种稳定性和打包兼容问题后,最终研发出了一套针对 Android ARSC/XML 文件格式的包体积优化方案,目前已经落地抖音,实现 2MB 以上的收益。
接下来,本文将深入讲解该方案的实现细节。
APK 资源格式优化
我们的核心思路是,以资源路径缩短为优化出发点,在最终的 APK 文件里,从resources.arsc
与 layout 布局文件的二进制文件格式着手,查看其内容结构,寻找可以删除的未使用字符串,优化文件名称或者文件里的字符串池。主要分为下面两个优化点。
资源路径缩短
资源格式修改
接入 AndResGuard 后,资源文件 res 目录 -> r,其中的子文件夹和文件名也都被混淆,即:
res/anim/abc_fade_in.xml -> r/a/a.xml
这是为了减少资源文件路径,从而减少包体积,自然联想到,是否还能进一步减少资源文件路径呢?显然,如果能将所有文件都放在 r 目录下,将中间的子文件夹去掉,则可以进一步减少资源文件路径和 zip 节点数量,一定还有包体收益;顺便可以将文件名的后缀去掉,也可以减少文件路径,即:
r/a/a.xml -> r/a
r/a/b.png -> r/b

由于修改资源文件名称需要修改resources.arsc
文件,这里对resources.arsc
的文件格式分析下: