编译优化与构建加速:Gradle构建优化
说实话,做Android开发这么多年,我最怕的就是等编译。尤其是大项目,改一行代码,等三分钟编译,那种感觉就像看着沙漏等下班。今天我们就聊聊怎么让Gradle跑得快一点,再快一点。
增量编译:别每次都从头来
增量编译这个概念,说白了就是「只编译改动的部分」。Gradle其实默认就支持,但很多人没用好。
我遇到过最典型的场景:一个同事改了资源文件里的一个字符串,结果整个项目重新编译了一遍。为什么?因为他把资源文件放在了src/main/res下,但Gradle的增量编译对资源文件的变更比较敏感。
怎么确认增量编译生效了?看编译日志:
// 增量编译生效时,你会看到类似这样的输出
:app:compileDebugKotlin UP-TO-DATE
:app:compileDebugJavaWithJavac UP-TO-DATE
如果看到的是EXECUTING而不是UP-TO-DATE,说明这次没有走增量。
并行编译:让CPU多干点活
现在的开发机哪个不是8核16线程?但Gradle默认只用一个线程干活,你说浪费不浪费?
在gradle.properties里加上这两行:
org.gradle.parallel=true
org.gradle.workers.max=4
并行编译的原理,是把多个模块的编译任务拆开,同时跑。比如你的项目有app、core、network三个模块,它们之间如果没有依赖关系,就可以同时编译。
KSP vs KAPT:注解处理器的选择
这个我得好好说说。KAPT(Kotlin Annotation Processing Tool)是Google早期推出的方案,但它有个问题——它会把Kotlin代码先转成Java桩文件,然后再走Java的注解处理器流程。这一步非常慢。
KSP(Kotlin Symbol Processing)是后来出的,它直接处理Kotlin的语法树,跳过了转Java那一步。速度提升非常明显。
| 对比项 | KAPT | KSP |
|---|---|---|
| 处理速度 | 慢(需要生成桩文件) | 快(直接处理语法树) |
| 兼容性 | 支持所有Java注解处理器 | 需要库作者适配 |
| 编译时间 | 基准 | 通常快2-3倍 |
| 适用场景 | 老项目、未适配KSP的库 | 新项目、已适配的库 |
我个人的习惯是:能用KSP就用KSP。像Room、Glide、Moshi这些主流库,早就支持KSP了。迁移也很简单:
// 替换前(KAPT)
plugins {
id 'org.jetbrains.kotlin.kapt'
}
dependencies {
kapt "androidx.room:room-compiler:2.6.0"
}
// 替换后(KSP)
plugins {
id 'com.google.devtools.ksp'
}
dependencies {
ksp "androidx.room:room-compiler:2.6.0"
}
迁移之后,我那个项目的编译时间从4分20秒降到了1分50秒。嗯,这个数字我记得很清楚。
R8全量混淆与资源缩减
R8是ProGuard的升级版,它不只是做混淆,还做代码优化和资源缩减。说白了,就是帮你把APK「瘦身」。
全量混淆的意思是,不只是混淆你的代码,还把第三方库的代码也混淆了。这样APK体积更小,反编译也更难。
在build.gradle里这样配置:
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
注意shrinkResources true这个配置。它会在混淆之后,自动移除未被引用的资源文件。比如你项目里有一百张图片,但实际只用了五十张,剩下的就会被删掉。
shrinkResources踩过坑。项目里用getIdentifier()动态获取资源ID,结果R8把那些资源当成「未使用」给删了。运行时直接崩溃。解决方案是在proguard-rules.pro里加规则:
-keep class **.R$* { *; }
R8的优化级别有几种:
- ProGuard模式:兼容旧规则,优化较少
- R8全量模式:默认开启,优化力度大
- R8完全模式:
android.enableR8.fullMode=true,最激进
我建议新项目直接用R8全量模式。老项目可以先在测试环境跑一遍,看看有没有问题。
知识体系总览
下面这张图,是我对编译优化这块的理解。你可以把它当成一个检查清单:
你看,整个体系其实就三大块:编译加速、注解处理优化、打包优化。每一块都有对应的落地手段。
最后说一句:优化不是一蹴而就的。我建议你先做一次编译耗时分析,找到瓶颈在哪,然后对症下药。别一上来就全改,改完发现某个配置不兼容,又得回滚,那才叫浪费时间。