Gradle带类型Copy任务正常,非类型任务copy闭包执行失败原因咨询
这绝对是Gradle新手最容易踩的阶段坑之一,核心问题出在Gradle的配置阶段和执行阶段的差异,咱们把你的代码拆解开来分析:
1. 非类型任务失败的原因
先看你最初写的这段代码:
task unpackBundle(dependsOn: bundleWeb){ copy{ from zipTree('build/web.zip') into 'build/exploded' } }
你以为dependsOn: bundleWeb会让copy代码等bundleWeb执行完再跑?其实不是!
Gradle构建分为两个关键阶段:
- 配置阶段:Gradle会先解析所有任务的配置,执行所有任务配置块里的代码(就是大括号里的内容)。
- 执行阶段:才会按照依赖顺序执行真正的任务动作。
你的copy{...}代码直接写在了任务的配置块里,所以在配置阶段就会被执行——这时候bundleWeb任务还没开始运行,build/web.zip根本还没生成,自然会报“文件不存在”的错误。dependsOn只是告诉Gradle任务的执行顺序,但管不了配置阶段的代码执行时机。
2. Copy类型任务正常的原因
再看修改后的Copy类型任务:
task unpackBundle(type: Copy, dependsOn: bundleWeb){ from zipTree('build/web.zip') into 'build/exploded' }
Gradle的内置类型任务(比如Copy、Zip)做了一个很重要的区分:配置块里的代码只是定义任务要做什么,而不是立刻去做。
这里的from和into只是在给CopySpec设置参数,记录复制的规则,真正的复制动作会被延迟到执行阶段。而因为你指定了dependsOn: bundleWeb,Gradle会先执行完bundleWeb生成zip文件,再执行unpackBundle的复制操作——这时候zip文件已经存在了,所以一切正常。
3. 用普通任务实现的正确姿势
如果你不想用Copy类型任务,也可以通过doLast闭包来修复:
task unpackBundle(dependsOn: bundleWeb){ doLast { copy{ from zipTree('build/web.zip') into 'build/exploded' } } }
doLast里的代码会被延迟到任务执行阶段才运行,这时候bundleWeb已经完成,zip文件生成,复制自然能成功。
总结
你并没有误解project.copy()的用法,只是没搞清楚Gradle的阶段模型。内置类型任务(比如Copy)帮你封装了“配置-执行”的分离逻辑,而普通任务的配置块代码会立刻执行,这才导致了依赖任务还没完成就去操作不存在的文件。
内容的提问来源于stack exchange,提问作者Mercato

