Skip to content

常见深坑 (Pitfalls)

Gradle 最让人困惑的地方在于它的“执行逻辑”。很多开发者习惯了顺序执行的代码,但在 Gradle 中,如果不理解生命周期,代码的行为会完全超出你的预期。

1. 配置阶段与执行阶段 (核心深坑)

致命错误:在配置阶段执行耗时操作

kotlin
// build.gradle.kts
tasks.register("myTask") {
    // 坑:这里的代码在“配置阶段”运行,无论你运行哪个任务,它都会执行!
    val result = URL("https://api.example.com").readText() 
    
    doLast {
        // 只有运行 ./gradlew myTask 时,这里的代码才执行
        println("Result: \$result")
    }
}

后果:每次同步项目(Sync)或运行任何 Task,都会发起网络请求,导致 IDE 极其卡顿。 正确做法:始终将逻辑放在 doLast { ... }doFirst { ... } 中。

2. 任务创建:create vs register

任务配置规避 (Task Configuration Avoidance)

  • tasks.create(...): 立即创建并配置任务(即使没用到也会拖慢配置速度)。
  • tasks.register(...): 推荐。只有当任务被真正调用时,才会进行配置。

3. 依赖配置:使用 +latest.release

稳定性风险

使用 implementation("com.example:lib:+") 看起来很省事,但它是生产环境的灾难。

  • 后果 A: 每次编译结果可能不同(因为远程库更新了)。
  • 后果 B: 导致构建不可离线(Gradle 必须联网检查更新)。
  • 后果 C: 缓存频繁失效。 正确做法:始终指定明确的版本号,或使用 Version Catalog 统一管理。

4. 绝对路径硬编码

破坏缓存

在任务中使用 File("C:/Users/Admin/Project/...") 这种绝对路径。

后果:该 Task 的编译结果无法在同事的机器或 CI 服务器上命中缓存。 正确做法:使用 project.layout.projectDirectory.file(...) 获取相对路径。

5. 滥用 afterEvaluate

为什么专家不建议用 afterEvaluate?

很多开发者为了解决“拿不到属性”的问题,习惯性套一层 afterEvaluate { ... }

  1. 它会使构建逻辑变得难以调试(执行顺序变得模糊)。
  2. 多模块项目中,它会导致复杂的竞态条件。 正确做法:优先使用 Lazy API (Property/Provider)