Gradle 编译太慢?我是如何把构建时间从 5 分钟优化到 40 秒的

2 阅读4分钟

作为一名 Android 开发者,世界上最遥远的距离不是生与死,而是我改了一行代码,点击了 "Run",然后看着 Gradle 的进度条在 Building... 处停滞不前。

以前我的项目全量编译一次要 5 分钟,增量编译也要 1-2 分钟。这期间我甚至能去冲杯咖啡、回几个消息,有时候甚至忘了自己刚才为什么要跑代码。上周我终于忍无可忍,花了一天时间对项目的构建系统做了一次“大手术”。

结果非常感人:全量编译降到了 40 秒左右,增量编译更是秒级响应。

今天不谈虚的,直接分享我这次优化的实战过程,希望能帮你省下那些盯着进度条发呆的时间。

第一步:知己知彼(Build Analyzer)

在动手改配置之前,你得先知道慢在哪里。盲目加大内存不一定有用。

Android Studio 自带的 Build Analyzer 是个神器。

  • 点击 AS 右侧的 Build 标签。
  • 编译完成后,点击 Build Analyzer 选项卡。

它会直接告诉你哪些 Task 耗时最长,或者是否有插件在拖后腿。我第一次跑的时候,发现竟然有两个老旧的 Gradle 插件在 configuration 阶段就卡了 30 秒。果断移除或升级这些陈旧插件,这是优化的第一刀。

第二步:薅 Gradle 的羊毛(gradle.properties 配置)

这是性价比最高的一步,改几个参数就能见效。打开你项目根目录下的 gradle.properties,检查以下配置:

1. 开启并行编译与守护进程

# 开启 Gradle 守护进程,复用 JVM 实例
org.gradle.daemon=true

# 开启并行编译,利用多核 CPU 优势(这个提升巨大)
org.gradle.parallel=true

# 开启构建缓存,复用之前的构建产物
org.gradle.caching=true

2. 调整 JVM 内存 很多时候慢是因为内存不够,导致 Gradle 频繁 GC。如果你的电脑是 16GB 或 32GB 内存,千万别吝啬。

# 给 Gradle 分配足够的堆内存(根据你电脑配置调整,我是 M2 Pro,给了 4G)
org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=1024m -Dfile.encoding=UTF-8

注意:不要无脑给太大,给太大反而会导致 GC 停顿时间变长。一般 4G-6G 足够应付中大型项目。

第三步:告别 KAPT,拥抱 KSP

这是我这次优化中收益最大的一项。

如果你在用 Room, Glide, 或者 Dagger/Hilt,你大概率在用 kapt。Kapt 的原理是生成 Java 存根(Stubs),这不仅慢,而且容易打断 Gradle 的增量编译链。

Google 推出的 KSP (Kotlin Symbol Processing) 可以直接解析 Kotlin 代码,速度比 Kapt 快 2 倍以上。

迁移步骤很简单:

  1. libs.versions.tomlbuild.gradle 中引入 KSP 插件。
  2. 把所有的 kapt 关键字替换为 ksp
// 以前
kapt "androidx.room:room-compiler:$room_version"

// 现在
ksp "androidx.room:room-compiler:$room_version"

迁移完这一波,我的编译时间直接砍掉了一分半钟。

第四步:开启 Configuration Cache(配置缓存)

Gradle 的生命周期分为:初始化 -> 配置 -> 执行。 大型项目中,光是“配置”阶段(解析所有 build.gradle 文件)就要花很久。

开启 Configuration Cache 后,Gradle 会缓存配置阶段的结果。第二次构建时,直接跳过配置阶段,直奔主题。

gradle.properties 中添加:

org.gradle.configuration-cache=true

排雷预警: 开启这个功能可能会报错,因为某些老旧插件或自定义 Task 可能不兼容(比如在配置阶段读取了系统时间或环境变量)。你需要根据报错信息修一修脚本,但这个折腾绝对值得,它能让你的增量构建瞬间起飞。

第五步:剔除 Debug 包中不必要的资源处理

我们在开发阶段(Debug)其实不需要很多耗时的操作,比如资源压缩、Crashlytics 上传符号表等。

app/build.gradle 中做如下优化:

android {
    buildTypes {
        debug {
            // 关闭 Crashlytics 构建 ID 生成(开发时不需要)
            ext.enableCrashlytics = false
            // 关闭 PNG 压缩(开发时用不到那么小的包)
            aaptOptions.cruncherEnabled = false
            // 甚至可以配置只编译当前连接设备的架构(比如只打 arm64-v8a)
            splits.abi.enable = false
            splits.density.enable = false
        }
    }
}

这能省下很多无意义的 I/O 操作。

总结

做完这一套“组合拳”:

  1. 基础配置:并行、缓存、大内存。
  2. 核心替换:KAPT -> KSP。
  3. 黑科技:Configuration Cache。
  4. 减负:Debug 模式剔除无用 Task。

我的项目从冷启动 5 分钟变成了 40 秒左右,热启动(改几行代码)通常在 5-8 秒内完成。

这种流畅感,真的会让你爱上写代码(起码不讨厌按 Run 了)。如果你也被 Gradle 折磨,不妨今晚就试试这几招。


P.S. 如果以上都没用,可能你真的需要换一台 M 芯片的 Mac 了……(逃)