19、构建脚本调试:Gradle日志级别、Stacktrace分析、断点调试Gradle脚本、常见错误排查
说实话,Gradle 脚本写多了,谁还没遇到过几个玄学问题?
我记得刚接手一个大型模块化项目时,构建突然就挂了,日志里就一行「Task failed with an exception」。我当时盯着屏幕看了十分钟,愣是没找到原因。后来才发现,是我压根没打开正确的日志级别。
这一章,我就把调试 Gradle 脚本的看家本事都掏出来。从日志级别到断点调试,再到那些你一定会踩的坑,咱们一个一个过。
19.1 Gradle 日志级别:你的第一道防线
Gradle 的日志系统其实挺贴心的。它分了六个级别,从安静到啰嗦,任你挑选。
| 日志级别 | 命令行参数 | 输出内容 |
|---|---|---|
| ERROR | -q 或 --quiet | 只输出错误信息 |
| WARNING | -w 或 --warn | 错误 + 警告 |
| LIFECYCLE | (默认) | 构建生命周期关键节点 |
| INFO | -i 或 --info | 更详细的进度信息 |
| DEBUG | -d 或 --debug | 所有细节,包括堆栈 |
我个人习惯,平时用默认的 LIFECYCLE 就够了。但一旦出问题,我第一件事就是加 -i 或 -d。
--info,如果还看不出问题,再上 --debug。
举个例子,你想看某个 Task 到底有没有被执行:
./gradlew assembleDebug --info | grep "Task :app:"
这样过滤一下,只看你关心的 Task,效率高很多。
19.2 Stacktrace 分析:别怕那堆调用栈
很多同学看到 Stacktrace 就头大。其实它没那么可怕。
Gradle 提供了两种 Stacktrace:
- 简短模式(-s): 只输出跟 Gradle 脚本相关的调用栈。适合定位脚本语法错误。
- 完整模式(-S): 输出所有调用栈,包括 Gradle 内部代码。适合定位插件或构建逻辑的深层问题。
我在项目中遇到过最典型的情况:自定义 Task 执行时报 NullPointerException。用 -s 一看,发现是我在 doLast 里引用了一个还没初始化的变量。
19.3 断点调试 Gradle 脚本:像调试 Java 一样调试 Groovy
嗯,这里要注意。很多人不知道 Gradle 脚本其实是可以打断点的。
你想想看,如果能在 IDE 里一步步跟踪脚本执行,那排查问题的效率能提升多少?
具体做法很简单:
- 在 Android Studio 或 IntelliJ IDEA 中,打开你的
build.gradle文件。 - 在行号旁边点击,打上断点。
- 在终端执行:
./gradlew assembleDebug -Dorg.gradle.debug=true --no-daemon - Gradle 会启动一个 JVM 并等待调试器连接。在 IDE 中创建一个「Remote JVM Debug」配置,端口默认是 5005。
- 启动调试,IDE 就会停在你的断点处。
--no-daemon,否则调试器可能连不上。另外,调试的是 Groovy 脚本,不是 Java 代码,所以有些 Java 调试技巧可能不适用。
我曾经用这个方法,花了半小时就定位了一个插件里的资源冲突问题。要是靠加日志打印,估计得折腾一整天。
19.4 常见错误排查:那些年我们踩过的坑
下面这几个错误,我敢说你迟早会遇到。提前了解一下,能省不少时间。
19.4.1 依赖冲突
错误信息通常是:Conflict with dependency ... 或 Duplicate class ...
排查命令:
./gradlew :app:dependencies --configuration debugRuntimeClasspath
这个命令会输出完整的依赖树。你一眼就能看出哪个库被引用了多个版本。
force = true 或 exclude 来统一版本,更干净。
19.4.2 Task 执行顺序错乱
症状:某个 Task 执行时,依赖的产物还没生成。
原因:dependsOn 或 mustRunAfter 没写对。
排查方法:
./gradlew :app:assembleDebug --dry-run
这个命令不会真正执行,只会打印出 Task 的执行顺序。你一看就知道哪里不对。
19.4.3 配置阶段耗时过长
症状:构建卡在「Configuring」阶段很久。
原因:通常是 allprojects 或 subprojects 里写了太多耗时操作。
排查方法:
./gradlew --profile assembleDebug
这个命令会生成一份 HTML 报告,详细列出每个阶段和每个 Task 的耗时。我上次用这个发现,一个同事在 subprojects 里做了网络请求,直接拖慢了整个构建。
19.4.4 插件版本不兼容
错误信息:Plugin with id 'xxx' not found 或 Could not find method xxx()
原因:插件版本和 Gradle 版本不匹配。
解决方案:去官方文档查兼容性矩阵。别自己瞎猜。
19.5 知识体系总览
下面这张图,把本章的核心逻辑串起来了。你可以把它当作调试时的检查清单。
说白了,调试 Gradle 脚本没什么神秘的。就是先定位问题范围,然后选择合适的日志级别或调试工具,最后根据输出信息去排查。多练几次,你也能成为团队里的 Gradle 救火队员。
公众号:蓝海资料掘金营,微信 deep3321