升级Gradle后Ant闭包触发配置缓存报错,求解决方法
问题描述
我创建了一个用于复制并FTP传输安装包的Gradle任务,原脚本如下:
task ftp(dependsOn: "copyApk") { doLast { ant { taskdef(name: 'ftp', classname: 'org.apache.tools.ant.taskdefs.optional.net.FTP', classpath: configurations.ftpAntTask.asPath) ftp(server: "ftp.mydomain.com", userid: "ftp.mydomain.com|administrator", password: "adkjadfsid", remoteDir: "download") { fileset(dir: "E:/.../download/") { include(name: "my-app.apk") } } } } }
该脚本正常运行多年。近期我将Android Studio升级至Giraffe版本,同时升级了Gradle等一系列组件,并按照Android Studio的建议将任务脚本修改为:
tasks.register('ftp') { dependsOn "copyApk" doLast { ant { taskdef(name: 'ftp', classname: 'org.apache.tools.ant.taskdefs.optional.net.FTP', classpath: configurations.ftpAntTask.asPath) ftp(server: "ftp.mydomain.com", userid: "ftp.mydomain.com|administrator", password: "adkjadfsid", remoteDir: "download") { fileset(dir: "E:/.../download/") { include(name: "my-app.apk") } } } } }
运行该任务时出现以下错误:
Cannot reference a Gradle script object from a Groovy closure as these are not supported with the configuration cache.
问题出在ant {这一行,需要解决思路。
解决思路
错误根源是Gradle配置缓存机制不允许在Groovy闭包中直接引用Gradle脚本对象(比如configurations),而ant {}闭包会隐式持有脚本上下文,导致序列化失败。以下是几种可行的修复方案:
方案1:提前获取配置路径,避免闭包内引用Gradle对象
在任务的配置阶段提前把configurations.ftpAntTask.asPath的值存为变量,再在doLast闭包中使用,切断闭包与Gradle配置对象的直接关联:
tasks.register('ftp') { dependsOn "copyApk" // 配置阶段提前获取classpath路径 def ftpAntClasspath = configurations.ftpAntTask.asPath doLast { ant.taskdef(name: 'ftp', classname: 'org.apache.tools.ant.taskdefs.optional.net.FTP', classpath: ftpAntClasspath) ant.ftp(server: "ftp.mydomain.com", userid: "ftp.mydomain.com|administrator", password: "adkjadfsid", remoteDir: "download") { fileset(dir: "E:/.../download/") { include(name: "my-app.apk") } } } }
方案2:显式创建AntBuilder实例,避免隐式脚本上下文
改用显式实例化AntBuilder的方式,替代Groovy DSL的ant {}闭包,彻底切断闭包与Gradle脚本对象的隐式关联:
tasks.register('ftp') { dependsOn "copyApk" doLast { def antBuilder = new AntBuilder() antBuilder.taskdef(name: 'ftp', classname: 'org.apache.tools.ant.taskdefs.optional.net.FTP', classpath: configurations.ftpAntTask.asPath) antBuilder.ftp(server: "ftp.mydomain.com", userid: "ftp.mydomain.com|administrator", password: "adkjadfsid", remoteDir: "download") { fileset(dir: "E:/.../download/") { include(name: "my-app.apk") } } } }
方案3:临时禁用该任务的配置缓存(不推荐)
如果暂时不想适配配置缓存,可以给单个任务禁用配置缓存,但这会失去配置缓存带来的性能优化:
tasks.register('ftp') { dependsOn "copyApk" // 禁用该任务的配置缓存 notCompatibleWithConfigurationCache("使用Ant闭包无法兼容配置缓存") doLast { ant { taskdef(name: 'ftp', classname: 'org.apache.tools.ant.taskdefs.optional.net.FTP', classpath: configurations.ftpAntTask.asPath) ftp(server: "ftp.mydomain.com", userid: "ftp.mydomain.com|administrator", password: "adkjadfsid", remoteDir: "download") { fileset(dir: "E:/.../download/") { include(name: "my-app.apk") } } } } }
内容的提问来源于stack exchange,提问作者Hong
相关产品推荐
相关产品推荐

