Gradle运行含java.io.Console终端API应用异常,如何让Gradle不干扰终端访问?
解决方案
这个问题本质是Gradle默认会对JavaExec任务的输入输出流做包装,用来实现自身的日志、进度条等功能,导致你的应用拿不到真实的终端句柄。下面给你几个可行的解决办法:
1. 用Gradle 7.0+的terminal属性(最推荐)
从Gradle 7.0开始,JavaExec任务新增了terminal属性,只要把它设置为TerminalMode.ATTACHED,就能让应用直接附加到当前终端,跳过Gradle的流包装。
如果是Kotlin DSL,配置如下:
// 针对所有JavaExec任务 tasks.withType<JavaExec> { terminal = TerminalMode.ATTACHED } // 或者只针对run任务 private val run: JavaExec by tasks run.apply { terminal = TerminalMode.ATTACHED }
如果是Groovy DSL:
tasks.withType(JavaExec) { terminal = TerminalMode.ATTACHED }
这个配置会让Gradle把真实的终端输入、输出、错误流直接传递给你的应用,System.console()就能正常拿到实例,终端操作也能正常工作。
2. 配合application插件的配置
如果你用了Gradle的application插件,也可以直接在application扩展里配置run任务的终端模式:
Kotlin DSL:
application { run { terminal = TerminalMode.ATTACHED } }
Groovy DSL:
application { run { terminal = TerminalMode.ATTACHED } }
3. 旧版Gradle的替代方案(Gradle <7.0)
如果你的Gradle版本低于7.0,没有terminal属性,可以通过execSpec强制使用系统原生的流,同时添加JVM参数确保Console可用:
Kotlin DSL:
tasks.withType<JavaExec> { execSpec { standardInput = System.`in` standardOutput = System.out errorOutput = System.err isRedirectErrorStream = false } // 添加JVM参数,确保Java能识别到终端 jvmArgs("-Djava.awt.headless=false") }
不过这个方案在复杂场景下可能不如TerminalMode.ATTACHED稳定,建议尽量升级到Gradle 7+版本。
验证效果
配置完成后,再运行gradle run(可以加--console=plain避免Gradle自身的输出干扰),你的应用应该就能正常识别终端了:System.console()不再返回null,加粗、彩色文本能正常显示,交互式提示也能正常工作。
内容的提问来源于stack exchange,提问作者Андрей Щеглов
相关产品推荐
相关产品推荐

