minSdk 从 26 升到 31 ,打包体积变大3倍 ,packaging dex 了解一下
minSdk 从 26 升到 31 ,打包体积变大3倍
1. 先分清三个「大小」
很多人一看到几十 MB 的.apk就慌,先建立三个概念:
| 概念 | 大致含义 | 谁在看 |
|---|---|---|
| APK 文件大小 | 你在资源管理器里看到的文件体积,本质是ZIP 包 | 你传文件、看磁盘 |
| ZIP 里每项「未压缩大小」 | 各文件「真实字节数」,zip 里可压缩或未压缩 | 分析工具 / 脚本 |
| 装到手机后的占用 | 系统解压、优化(dex/oat)后的结果,和 APK 不总一致 | 用户「存储空间」 |
学什么:优化「下载/拷贝」时往往盯 APK 文件;优化「手机里占多少」有时要看安装后数据。APK 变大 ≠ 业务代码突然多了几万行。
2..apk本质上是一个 ZIP
双击改后缀或用解压软件打开,你会看到类似:
classes.dex,classes2.dex, … ——应用代码(Kotlin/Java 编译结果)lib/<abi>/xxx.so——原生库(JNI,视频解码等常在这里面)resources.arsc、res/——资源AndroidManifest.xml(二进制形式)等
学什么:想查「体积从哪来」,可以先看哪几个 dex / 哪几个 .so 最大。
3. Debug 包为什么常比 Release「显胖」?
常见原因包括(不必全中,你的项目可能只占其中几条):
- 默认不开代码压缩:
minifyEnabled/ R8 关掉时,没用到的类也会打进 DEX。 **debugImplementation**:只在 debug 变体里打进包的工具(例如 Compose 的ui-tooling),release 里没有。- 调试信息:符号、行号等会让 DEX 略大。
但Debug 不是唯一原因。有时Release 也没开混淆,那 debug/release 的代码体积差距会缩小;真正「从 25MB 飙到 75MB」也可能是下面第 6 节的情况。
4. 依赖库是最大的常客
带视频播放 / 大屏展示的 Android 应用,典型的大头有:
- Jetpack Compose + Material3:UI 框架本身 + 运行时。
**material-icons-extended**:成套图标,体积很容易涨一截;若只用了少数图标,可考虑改成只依赖需要的子集或改用material-icons-core+ 按需资源。- Media3 / ExoPlayer:播放器、解码相关,常带native
.so,多 ABI 会成倍増大(未单独拆包时)。
学什么:同样的业务,依赖选得「重」,APK 就容易大;这和「多写了几行业务 Kotlin」通常不在一个数量级——后者往往只有几 KB 量级。
5. 一次小迭代与体积(几乎无关)
某次改动里增加了:设备标识相关的读取逻辑、与后台交互的展示名字段默认值、以及少量网络相关权限声明。
这些对DEX 体量影响极小;不会单独解释「25MB → 75MB」这种量级。
6. 本案例的关键发现:为什么「旧备份」约 25MB,当前约 75MB?
6.1 对比两份工程配置
- 两份工程的
app/build.gradle.kts里,依赖列表几乎一模一样。 - 唯一明显的默认配置差异:旧备份
**minSdk = 26**,当前**minSdk = 31**。
6.2 对比两个已经打好的app-debug.apk
用脚本或工具看ZIP 里每个classes*.dex的「压缩后大小」和「未压缩大小」:
- 旧备份 APK:
CompressedLength明显小于原始长度 → DEX 在 ZIP 里被压缩存储。 - 当前 APK:多数 dex 的
CompressedLength == 原始长度→ DEX 在 ZIP 里不压缩(STORED)。
再算一遍 ZIP 内所有条目的「未压缩字节总和」:两份其实在同一个量级(约七千多万字节),说明装进包里的代码/资源体量相近,差的是压缩与否反映在「文件体积」上。
6.3 官方行为(你要记的结论)
Android Gradle Plugin(AGP)的约定大致是:
- 当
**minSdk >= 28** 且未另行设置时,默认把 APK 里的 DEX 以不压缩方式放入 ZIP(利于安装与运行时的映射等考量)。 **minSdk较低**(例如 26)时,更容易仍走压缩 DEX的旧习惯,于是同一个依赖、同量级代码,你看到的APK 文件却可能小很多。
所以:不是「开了 debug」单独造成的落差,而是**minSdk抬高后触发了 DEX 在 APK 内的默认打包策略**,再叠加第 4 节的大依赖,文件看起来就特别胖。
7. 若你希望「APK 文件」再次接近小体积(例如只侧传 APK)
在**app/build.gradle.kts** 的android { }里可以增加(与现有packaging合并即可):
packaging{dex{useLegacyPackaging=true}}含义:让 DEX 按「旧习惯」在 APK 里被压缩,文件往往明显变小。取舍与细节以 DexPackagingOptions 及 AGP 发行说明为准;若走Google Play 的 AAB处理,不完全等同本地 APK。,分发体积还会由 Play 再
8. 若想系统性「减肥」(进阶路线)
可以按顺序尝试(每项改完打 release、真机测核心业务流程):
- Release +
minifyEnabled = true+ 写好 Proguard 规则(Kotlin/Compose/反射/XML 要测全)。 **shrinkResources = true**(配合 minify)。- 拆分 ABI(
abiFilters或上架用 AAB),避免「一台机器只跑 arm64,却打进去 x86」。 - 审视
**material-icons-extended** 是否可瘦身。 - 查阅 Media3/ExoPlayer 文档,按需模块,避免引入不需要的解码器。
9. 你可以自己动手的小练习
- 用解压软件打开
app-debug.apk,按文件大小排序,记下最大的 5 个条目。 - 把当前工程的
minSdk临时改成26(仅本地试验),clean 后重装打 debug,对比 APK 文件大小(理解后请改回你产品需要的minSdk)。 - 加上第 7 节的
useLegacyPackaging = true,再对比一次 APK 大小。
10. 一页纸总结
- APK = ZIP;大头常在DEX和
**.so**。 - Debug会多一些调试向依赖,但不是本次「25 vs 75MB」的主因。
- 同依赖、同代码量级下,
**minSdk从 26 升到 31** 会触发DEX 在 APK 内默认不压缩,文件体积陡增,和手机里「逻辑体积」不是一回事。 - 少量业务逻辑改动不会让包突然大几十 MB。
- 要小文件:可考虑
**dex { useLegacyPackaging = true }**,再配合混淆、资源收缩、ABI 拆分做长期优化。
基于同一应用「旧备份工程」与「当前工程」的配置对比,以及对两份 debug APK 内 ZIP 条目的检查整理,方便日后遇到「包怎么变大了」时能按步骤自查。
