如何用单个名称引用多个Gradle Task输出?或归集多Task输出
如何用一个名称引用多个Task的输出(归集Task输出)
这问题我在项目里遇到过好多次!Gradle里确实有更优雅的方式来归集多个任务的输出,不用每次都挨个手动列举。下面给你几个实用的解决方案,按需选择:
方案1:通过任务筛选直接归集输出
如果你的taskA*任务有统一的命名规则(比如都以taskA开头),或者属于同一个分组,可以直接筛选出这些任务,然后收集它们的输出:
plugins { id 'distribution' } task taskA0 { outputs.dir "$buildDir/a0" doLast { mkdir outputs.files.singleFile file(outputs.files.singleFile, 'content.txt').text = 'A0' } } task taskA1 { outputs.dir "$buildDir/a1" doLast { mkdir outputs.files.singleFile file(outputs.files.singleFile, 'content.txt').text = 'A1' } } task taskA2 { outputs.dir "$buildDir/a2" doLast { mkdir outputs.files.singleFile file(outputs.files.singleFile, 'content.txt').text = 'A2' } } task allA { dependsOn taskA0, taskA1, taskA2 } distributions { main { contents { // 方式1:按名称前缀筛选任务,收集它们的输出 from tasks.matching { it.name.startsWith('taskA') }.collect { it.outputs } // 如果你给任务加了统一分组,也可以这么筛选(更严谨) // task taskA0 { group 'myDistributionTasks' ... } // from tasks.withGroup('myDistributionTasks').collect { it.outputs } // 或者直接用allA的依赖列表来获取 // from allA.dependsOn.collect { project.tasks[it].outputs } } } }
这种方式的好处是无需额外新增任务,直接利用现有任务的特性筛选,后续新增taskA3时,只要命名/分组符合规则,distribution会自动包含它的输出。
方案2:创建专门的聚合输出任务
如果希望把输出归集逻辑封装起来,或者不想依赖命名/分组,可以创建一个专门的"聚合任务",让它拥有所有taskA*的输出:
plugins { id 'distribution' } task taskA0 { outputs.dir "$buildDir/a0" doLast { mkdir outputs.files.singleFile file(outputs.files.singleFile, 'content.txt').text = 'A0' } } task taskA1 { outputs.dir "$buildDir/a1" doLast { mkdir outputs.files.singleFile file(outputs.files.singleFile, 'content.txt').text = 'A1' } } task taskA2 { outputs.dir "$buildDir/a2" doLast { mkdir outputs.files.singleFile file(outputs.files.singleFile, 'content.txt').text = 'A2' } } // 创建聚合输出任务,专门归集所有taskA*的输出 task aggregateTaskAOutputs { // 把所有taskA*的输出设为这个任务的输出 outputs.files taskA0.outputs.files, taskA1.outputs.files, taskA2.outputs.files // 依赖所有taskA*,确保它们先执行 dependsOn taskA0, taskA1, taskA2 } // allA可以直接依赖这个聚合任务 task allA { dependsOn aggregateTaskAOutputs } distributions { main { contents { // 现在直接引用聚合任务的输出即可 from aggregateTaskAOutputs } } }
这个方案的优势是逻辑清晰,后续新增taskA3时,只需要修改aggregateTaskAOutputs的outputs和dependsOn,distribution部分完全不用动。而且这个任务本身有明确的输出,Gradle可以正确处理增量构建,不会重复执行不必要的步骤。
方案3:用Provider动态收集输出(Gradle 6.0+推荐)
如果你的项目用的是Gradle 6.0及以上版本,推荐用Provider来动态收集输出,符合Gradle的懒加载理念:
plugins { id 'distribution' } task taskA0 { outputs.dir "$buildDir/a0" doLast { mkdir outputs.files.singleFile file(outputs.files.singleFile, 'content.txt').text = 'A0' } } task taskA1 { outputs.dir "$buildDir/a1" doLast { mkdir outputs.files.singleFile file(outputs.files.singleFile, 'content.txt').text = 'A1' } } task taskA2 { outputs.dir "$buildDir/a2" doLast { mkdir outputs.files.singleFile file(outputs.files.singleFile, 'content.txt').text = 'A2' } } task allA { dependsOn taskA0, taskA1, taskA2 } // 定义一个Provider,动态获取所有taskA*的输出文件集合 def allTaskAOutputs = providers.provider { tasks.matching { it.name.startsWith('taskA') }.collectMany { it.outputs.files } } distributions { main { contents { from allTaskAOutputs } } }
这种方式的好处是懒加载,只有在Gradle真正需要获取输出的时候才会去筛选任务和收集输出,适合大型项目,能避免过早初始化任务带来的性能问题。
为什么直接from allA不行?
因为allA本身只是一个"依赖容器",没有定义任何outputs属性。Gradle不知道它的输出是什么,所以必须明确指定要包含的是它所依赖任务的输出,而不是任务本身。
内容的提问来源于stack exchange,提问作者Balz Guenat
相关产品推荐
相关产品推荐

