Android 缩小客户端体积之 so 方向

公司的 android 客户端大小已经达到了 60 多 MB,减小客户端体积的大小已经迫在眉睫。研究一下项目代码发现 android 工程 libs 下的 so 文件已经达到了 30 多 MB (压缩前的大小)。于是决定从 so 文件方面进行体积的优化。最终的结果是客户端大小减小了 8.7 MB。下面是详细的过程。

android 工程下有 armeabi 和 armeabi-v7a 两个文件夹,两个文件夹下各自有 10 多个 so 文件。比较两个文件夹下的 so 文件的 hash 值,一比较吓一跳,两个文件夹下有 13 个 so 文件的 hash 值是相同的。也就是说有 13 个 so 文件是重复的。(13 个 so 文件大小总共 15 MB )。

到这里可能有人会想直接把 armeabi 或者 armeabi-v7a 下面重复的 13 个 so 文件删除了。不过这是不可行的。首先看一张图:

图片

该图是说不同的 ABI 文件夹对应不同指令集的 cpu 。v5 架构 cpu 会加载 armeabi 文件夹下面的 so 文件,v7 架构的 cpu 会加载 armeabi-7a 下面的 so 文件夹。假如说 v7 架构的手机需要加载一个 a.so 文件,首先 系统会判断 armeabi-v7a 文件夹是否存在。如果存在直接加载 armeabi-v7a 下面的 a.so ,如果 armeabi-v7a 下面没有 a.so 文件,app 会直接闪退。如果工程下面没有 armeabi-v7a 文件夹,系统自动加载 armeabi 下面对应的 a.so 文件,假如 armeabi 下面也不存在 a.so 的话,程序也会闪退。

从 armeabi 的角度来看,直接删除 armeabi 下面重复的 13 个 so 文件是不可以的,目前公司项目需要支持低配的手机,所以 armeabi 文件夹下面的 so 文件是不能被删除的。
从 armeabi-v7a 的角度来看,直接删除 armeabi-v7a 下面重复的 13 个 so 文件会导致应用闪退。把整个 armeabi-v7a 删除掉也不好, 因为项目中 armeabi-v7a 有两个 so 文件是 支持 v7 架构的,它们与 armeabi 下面对应的 so 文件 hash 值是不一样的,直接删除掉整个 armeabi-v7a 文件夹会影响 app 的性能。

那有什么方案能既能支持老旧的手机设备又不会有性能的损耗呢?手淘和微信客户端的做法为我们提供了一种思路,如下图:




由上图可见微信 、手淘的客户端只保留了 armeabi 文件夹(微信和手淘 armeabi 文件夹下保留了几个 -v7a.so 文件,微信、淘宝客户端是在 app 运行的时候判断手机处理器类型决定是否加载 -v7a.so 文件)。

所以最终的方案是删除掉整个 armeabi-v7a 文件夹,将对性能有影响的 v7a 架构的 so 文件放到 armeabi 文件夹下。假如有个 a.so 文件对性能有较大影响,在 armeabi 文件夹放 a.so 和 a_v7a.so 两个 so 文件。代码这样写:

String abi = Build.CPU_ABI;
if ("arm64-v8a".equals(abi) || "armeabi-v7a".equals(abi)) {
        System.loadLibrary("a_v7a");
    } else {
        System.loadLibrary("a");
    }

按照上面这种方案实施后,公司 android 客户端大小缩减了 8.7 MB,心里真是很有成就感呢^-^。