常见深坑 (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 { ... }。
- 它会使构建逻辑变得难以调试(执行顺序变得模糊)。
- 多模块项目中,它会导致复杂的竞态条件。 正确做法:优先使用 Lazy API (Property/Provider)。