opoojkk

一次 Android APK 体积优化实录

lxx
目次

现状及问题 #

最近工作上有些变动,新接手的项目中发现 apk 的 Debug 包有 170 多 MB,Release 包也要 140 MB。 仔细看项目内容,其实并没有那么多东西。想要减小体积,首先得搞清楚从哪里下手,于是决定先分析一下应用的体积构成。

分析 #

将打包后的 apk 拖到 Android Studio 里,就能看到各部分的体积占比。

ABI #

lib 的体积挺惊人,占了 92.9MB。 这个目录是放 native 库的,来源通常有两种:

  1. 自己写的 native 代码(为了性能、安全或通用性);
  2. 第三方库自带的 native 文件。

第三方库为了支持更多设备,会同时包含多个 ABI。 先从这里下手,初步猜测是没过滤 ABI。

果然,ABI 支持得很全,连不用的都打进去了。

ABI(Application Binary Interface)指的是“应用二进制接口”, 也就是应用(或其原生库)与系统或其他模块在二进制层面所遵循的规则,比如指令集、函数调用约定、数据对齐、库格式、命名修饰(mangling)等。 简单来说,ABI 就是 CPU 支持的指令集

ABI 名称架构 / 指令集状态说明
armeabiARMv5(32 位)早期架构,NDK r17 起已废弃。
armeabi-v7aARMv7(32 位) + Thumb-2 + NEON早期主流架构,现已逐步淘汰。
arm64-v8aARMv8(64 位)当前主流,Google Play 要求支持。
x86Intel/AMD 32 位市场占比极低,仅部分设备或模拟器使用。
x86_64Intel/AMD 64 位同上,主要用于模拟器。
mips,mips64MIPS 架构曾支持,现已移除。

当前架构情况(2025) #

当前手机基本都是 64 位 ARM 架构,许多 armv8 设备都已经卡得不行,更不用说更早的 armv7。 过滤 ABI 很简单,在模块级 gradle 中加上:

1
abiFilters 'arm64-v8a'

省掉了 66.86MB

资源 #

第二大块体积来自资源。 Android 资源包含:图片、布局、字体、字符串、颜色、属性。 打包时通常会开启 isShrinkResources 去掉未使用资源,但正在使用的图片仍然会占据相当大空间。

图片体积往往以 MB 计,尤其是大尺寸 PNG。 常见格式有:

几种优化方式 #

  1. 算法压缩(TinyPNG、pngquant 等) 不影响质量,能显著减小体积。
  2. 降低质量 减小体积,但大图可能会糊。
  3. 改用 WebP 压缩率高,但部分旧系统仍有兼容风险。

三种方式中,第一种几乎没有副作用。 综合稳定性和收益,我选择了算法压缩。

我用 TinyPNG 来处理图片。 它的效果不错,但免费账号有调用限制,只能一次次通过网页上传压缩。

压缩前后效果对比:

从 32.5MB 缩减至 16.9MB,缩减 48%

代码 #

代码层面最常见的方式是 混淆。 混淆不仅能减小体积,也能提高反编译难度,可谓一举两得。

配置也很简单:

1
isMinifyEnabled true

大多数项目都会默认开启,这里不再赘述。

实操 #

当前阶段的优化主要是:

这些操作后,应用从 140.3MB → 58.3MB,整体缩减 58% ,效果明显。

回顾 #

上面这些是最基础、最常规的优化,不需要额外依赖,也不会影响功能。 除此之外,还可以考虑以下两种更深入的做法:

  1. 资源动态下发 除启动图、占位图、错误图外,其他资源可由服务端下发。 优点是包更轻,缺点是首启依赖网络。
  2. 插件化 / 模块拆分 只保留首页等必要模块,把购买、订单、播放等拆成独立 apk 以插件形式按需下载。 效果好,但工程量大。

防劣 #

ABI 配置一般不会变,但图片最容易劣化。 随着业务迭代,不断有新图片被引入。 为了防止包体积回涨,最好不要依赖人工检查,而是让持续集成自动化完成。

可以这样做:

这样既能保证体积稳定,又不会明显增加构建时间。

标签:
Categories: