为何将minSdkVersion从27升级到28会使APK大小翻倍?
最近我将项目的minSdkVersion从27升级到28后,编译签名发布版本的APK大小从9.2MB激增到20.3MB。仅改回27并清理重新编译后,APK大小又回到原来的水平。通过Android Studio的Analyze APK工具对比发现:
- 两个版本的引用方法数量完全相同
classes.dex和classes2.dex的原始大小从3.4MB/3.3MB跃升至9.3MB/8.2MB
补充信息:
targetSdkVersion为31- 应用不通过Google Play分发
- 代码压缩(
minifyEnabled)已关闭且因业务原因无法开启 - 测试了
minSdkVersion设为29、30、31、32、33的情况,发现28及以上版本间APK大小无明显差异
我更关注导致此现象的具体原因,而非减小体积的方案。
这背后的核心原因是Android Gradle Plugin(AGP)在minSdkVersion ≥28时,默认使用了针对Android 9+优化的Dex格式与编译策略,具体细节如下:
1. Dex格式版本升级到v039
从Android 9(API 28)开始,系统支持Dex格式版本039(旧版本系统最高支持035)。当minSdkVersion≥28时,AGP的D8编译器会默认生成v039格式的Dex文件:
- v039格式为了适配现代Android系统的运行时优化,放弃了旧格式中一些为节省体积设计的紧凑编码方式(比如某些常量池的压缩存储、字符串的精简索引)
- 虽然方法数量没有变化,但Dex文件的元数据、字节码指令的存储结构更“宽松”,直接导致单个Dex文件的体积显著增大
2. Desugaring策略的隐性调整
尽管你关闭了minifyEnabled,但AGP默认开启的**Desugaring(语法糖脱糖)**在minSdkVersion ≥28时会有不同的处理逻辑:
- 对于
minSdk <28的版本,脱糖过程会为Java 8+的API(比如Stream、Optional等)生成大量兼容桥接方法,但这些方法会被AGP的内部优化合并或精简,间接减小了Dex体积 - 而
minSdk ≥28时,系统原生支持大部分Java 8+ API,脱糖过程不需要生成兼容桥接方法,但会保留更多原生的字节码结构——这些结构的体积比精简后的桥接方法更大,不过你提到方法数相同,是因为桥接方法的数量被原生API的调用结构抵消了,整体方法数不变但字节码总占用空间增加
3. 取消旧版本的Dex压缩优化
针对minSdk <28的设备,AGP默认会启用一些专门的Dex压缩优化(比如针对低内存设备的compact Dex格式、类索引的压缩),这些优化会牺牲部分运行效率来减小体积;而minSdk ≥28时,现代Android设备的内存和性能足够,AGP会关闭这些优化,优先保证运行效率,从而导致Dex体积上升
这些变化都是AGP为适配新版本Android系统的默认行为,并非你的代码或配置出现问题——这也解释了为什么28及以上的minSdkVersion之间体积没有明显差异,因为它们都使用了相同的Dex格式与编译策略。
内容的提问来源于stack exchange,提问作者Daniel Oskarsson

