Android 的增量编译,到底省了多少时间
Android 的增量编译,到底省了多少时间
从一条 UP-TO-DATE 日志开始
前阵子升级一个老项目到 AGP 8.1.0 + Gradle 8.2.1 + Kotlin 1.9.10, clean build 时间从 3 分 20 秒涨到了 5 分钟出头。排查后发现是某个内部性能监控 SDK 还在用已经被废弃的 Transform API,导致 Gradle 在 Dexing 阶段回退到了兼容模式。但比 clean build 更让我困惑的是日常开发时的增量表现:有时候改一行日志,构建 15 秒就推到设备上;有时候只是改了一个 internal 方法的可见性,构建却飙到 1 分半。我本能地觉得"增量编译肯定比全量快",但到底快了多少、什么时候快、什么时候其实在"假增量",心里完全没谱。于是我用 Gradle Profiler 在一个 42 个模块、约 18 万行 Kotlin 代码的项目上跑了一组对比测试,结果和预想的不太一样。
Gradle 的增量边界:ABI 与实现体的区别
Gradle 的增量单元不是文件,而是 Task。Task 通过输入输出声明让 Gradle 追踪变化。从 Gradle 5.0 开始,Gradle 引入了 @CompileClasspath 注解,它和 @Classpath 的区别非常关键:前者只关心 Application Binary Interface(ABI),后者关心完整的文件内容哈希。如果上游模块改动的是方法体(实现体),没有触碰公开的方法签名、字段类型、类继承结构,那么下游模块的 compileClasspath 输入指纹不会变化,下游的 compileDebugKotlin 会直接标记为 UP-TO-DATE。
这就是为什么"改一行方法体"通常能极速完成。我在测试里修改了一个工具类的正则逻辑,不涉及任何公开 API 的变更。feature-login 模块的 compileDebugKotlin 跑了 6 秒,下游的 `feature