Gradle构建分析与Task详解

前言

我们现在已经对如何使用Gradle来构建Android工程有了认识,并且大致了解了Groovy的语法和Maven仓库的相关知识,本篇文章计划从原理和API接口角度来分析一下我们配置的脚本文件,以及是如何工作的,只有学会了如何查看API文档才能灵活的去配置构建。

我们已经知道Gradle中待编译的工程叫project,每个project由多个task来组成,而这些task就是具体完成任务的基本单位。你是否还记得第一次使用Android Studio来创建新工程,发现里面默认有很多任务,它们是怎么来的呢?它们又能做什么呢?

Gradle的Task列表

构建分析

Gradle是一个框架,作为框架,它负责定义流程和规则。而具体的编译工作则是通过插件的方式来完成的。比如编译Java有Java插件,编译Groovy有Groovy插件,编译Android APP有Android APP插件,编译Android Library有Android Library插件。

1
2
3
apply plugin: 'java'
apply plugin: 'groovy'
apply plugin: 'com.android.application'

唯一不同的是插件javagroovy是内置的标准gradle插件,而com.android.application是第三方插件。这个区别就在于是否需要使用dependencies { }来引入插件的库。

目前而言Gradle框架内置了4个语言相关插件(分别是:java、groovy、scala、antlr),后面可能会更多。这些插件添加了让各种语言可以在 JVM 中被编译和执行的支持。另外还内置了几个实验性的语言插件:assembler、c、cpp、objective-c、objective-cpp、windows-resource.

除了语言支持相关插件外还有一些集成插件,例如:

插件说明
application添加了一些用于运行和捆绑 Java 项目的任务作为命令行应用程序
maven添加将项目发布到 Maven 仓库的支持
war添加装配 web 应用程序的 WAR 文件的支持
maven-publish这个插件提供了一个新的 DSL,用于支持发布工件到 Maven 存储库,它改进了现有的 DSL

除了这些还有软件开发相关的插件,例如我们常用的wrapper等。

这里我们需要注意并关心的是这些插件都继承自一些基础插件,但是请注意,它们还没有被视为 Gradle 公共 API 的一部分。因此,这些插件都不在用户指南中记录。你可以参考它们的 API 文档来了解更多关于它们的信息。

插件说明
base添加标准的生命周期任务,并为归档任务默认进行合理的配置
java-base对项目添加源集的概念。它不会添加任何特定的源集
groovy-base向项目添加 Groovy 源集的概念
scala-base向项目添加 Scala 源集的概念
reporting-base将一些共享的约定属性添加到项目中,它们与报告的生成有关

我们暂且不去细究这些内置插件,来看看第三方插件com.android.application的使用。

Gradle基于Groovy,Groovy又基于Java。所以,Gradle执行的时候和Groovy一样,会把脚本转换成Java对象。Gradle主要有三种对象,这三种对象和三种不同的脚本文件对应,在gradle执行的时候,会将脚本转换成对应的对端:

  • Gradle对象:当我们执行gradle xxx或者什么的时候,gradle会从默认的配置脚本中构造出一个Gradle对象。在整个执行过程中,只有这么一个对象。Gradle对象的数据类型就是Gradle。我们一般很少去定制这个默认的配置脚本。
  • Project对象:每一个build.gradle会转换成一个Project对象。
  • Settings对象:显然,每一个settings.gradle都会转换成一个Settings对象。

当我们执行gradle的时候,gradle首先是按顺序解析各个gradle文件, 查看官方文档

第一步:根据settings.gradle配置来创建Settings对象。

1
include ':app', ':buildsrc'

第二步:根据Settings对象的配置来分别寻找build.gradle并创建Project对象。

第三步:检查和加载build.gradle配置中相关task和相关依赖。

在Project对象中调用了接口PluginAware的apply()函数,这其实就是加载插件了:

Modifier and TypeMethodDescription
voidapply​(Closure closure)Applies zero or more plugins or scripts.
voidapply​(Map<String,​?> options)Applies a plugin or script, using the given options provided as a map.
voidapply​(Action<? super ObjectConfigurationAction> action)Applies zero or more plugins or scripts.

此外每一个gradle脚本都实现了Script接口,此接口定义了很多可以在脚本中使用的属性和方法。

脚本块描述
allprojects { }配置此项目及每个子项目共同的属性
artifacts { }依赖配置也可以用来发布文件
buildscript { }用于声明gardle脚本自身所需要使用的资源,包括依赖项、maven仓库地址、第三方插件等
configurations { }配置此项目的依赖的配置文件
dependencies { }配置此项目的依赖项
repositories { }配置此项目的库存储
sourceSets { }配置此项目的源文件
subprojects { }配置此项目的子项目
publishing { }配置 PublishingExtension 添加发布插件

我们的Android Gradle 插件继承自Application,更多DSL相关官方文档请查看这里

现在来回答上面所提到的问题,事实上我们新建工程都会有很多固定的默认tasks,比如help,我们可以使用gradle help --task tasks来查看指定Task的帮助。同样的在Android Gradle插件中也默认创建了很多与之相关的tasks,这些task是构建Android工程的基础,涵盖了一些基础构建和自带其他工具构建任务, 下面列出几个常用的help分类的task。

| 分组 | task | type | 说明 |
| help | tasks | TaskReportTask |显示项目中的任务列表 |
| help | projects | ProjectReportTask | 显示构建中的项目列表 |
| help | dependencies | DependencyReportTask | 显示项目的依赖关系树 |

最后再强调一点,请详细查看该文档, 所有的基础task定义都在这里,这也是理解默认tasks的关键。

Task详解

我们前面已经提到如何去自定义一个task来执行一段任务,例如下面这样:

1
2
3
task testTask{
println "hello world"
}

你会发现这个task会在config testTask后执行,也就是说上面的打印会在代码配置阶段执行,其实很多时候我们需要的是在构建阶段执行,所以我们需要将逻辑定义在doFirst或者doLast方法中来执行。

1
2
3
4
5
6
7
8
9
10
11
task testTask{
println "hello world"
}

testTask.doFirst{
println "do First"
}

testTask.doLast{
println "do Last"
}

这样配置的执行结果如下(注意前面提到过doLast还有一种 <<的缩写形式):

1
2
3
4
$ hello world
$ app: testTask
$ do First
$ do Last

其实Gradle已经为我们提供了一些方便的基础Task,例如:Copy、Delete、Sync等,所以我们可以直接继承它们来实现对应逻辑。

更多基础Task可参考官方文档

1
task testTask(type: Copy) {  /* ... */}

我们还可以通过API的方式动态创建Task并制定参数,可以指定的参数如下:

参数含义默认值
nametask的名字不能为空,必须指定
typetask的父类DefaultTask
overwrite是否替换已经存在的taskfalse
dependsOntask依赖的task集合[]
grouptask属于哪个组null
descriptiontask的描述null
1
2
3
4
5
6
7
8
9
10
11
12
task myTask1 << {
println "execute myTask1"
}

task myTask2 << {
println "execute myTask2"
}

// 定义一个名字为rygTask的task,属于renyugang分组,并且依赖myTask1和myTask2两个task。
project.task('rygTask', group: "renyugang", description: "我自己的Task", dependsOn: ["myTask1", "myTask2"] ).doLast {
println "execute rygTask"
}

尝试执行gradle rygTask,结果如下:

1
2
3
4
5
6
7
8
:app:myTask1
execute myTask1

:app:myTask2
execute myTask2

:app:rygTask
execute rygTask

评论

Ajax Android AndroidStudio Animation Anroid Studio AppBarLayout Banner Buffer Bulma ByteBuffer CDN CMYK COM1 COM2 CSS Camera Raw, 直方图 Chrome ContentProvider CoordinatorLayout C语言 DML DOM Dagger Dagger2 Darktable Demo Document DownloadManage Element Error Exception Extensions File FileProvider Fresco Git GitHub GitLab Gradle Groovy HTML5 Handler HandlerThread Hexo Hybrid IDEA IO ImageMagick IntelliJ Intellij Interpolator JCenter JNI JS Java JavaScript JsBridge Kotlin Lab Lambda Lifecycle Linux Looper MVC MVP Maven MessageQueue Modbus Momentum MySQL NDK NIO NexT Next Nodejs ObjectAnimator Oracle VM Permission PhotoShop Physics Python RGB RS-232 RTU Retrofit Runnable RxAndroid RxJava SE0 Spring SpringBoot Statubar Task Theme Thread Tkinter UI UIKit UML VS Code ValueAnimator ViewPropertyAnimator Web Web前端 Workbench api apk by关键字 compileOnly css databases demo hexo hotfix html iOS icarus implementation init jQuery javascript launchModel logo merge mvp offset photos pug query rxjava2 scss servlet shell svg tkinter tomcat transition unicode utf-8 vector virtual box 七牛 下载 中介者模式 串口 主题 事件 享元模式 仓库 代理模式 位运算 依赖注入 修改,tables 光和色 内核 函数 函数式编程 分支 分析 创建 删除 动画 单例模式 压缩图片 发布 可空性 合并 同向性 后期 启动模式 命令 命令模式 响应式 响应式编程 图层 图床 图片压缩 图片处理 图片轮播 地球 域名 基础 增加 备忘录模式 外观模式 多线程 大爆炸 天气APP 太白山 奇点 字符集 存储引擎 宇宙 实践 属性 属性动画 工具 工厂模式 年终总结 异常 弱引用 恒星 打包 技巧 插件 摄影 操作系统 攻略 故事 数据库 数据类型 文件 新功能 旅行 旋转木马 时序图 时空 时间简史 曲线 杂谈 权限 架构 查询 标签选择器 样式 核心 框架 案例 桥接模式 模块化 模板引擎 模板方法模式 泛型 浅色状态栏 源码 瀑布流 热修复 版本 版本控制 状态栏 状态模式 生活 留言板 相册 相对论 知识点 码云 磁盘 科学 笔记 策略模式 类图 系统,发行版, GNU 索引 组件 组合模式 结构 编码 网易云信 网格布局 网站广播 网站通知 网络 美化 膨胀的宇宙 自定义 自定义View 自定义插件 蒙版 虚拟 补码 表单 装饰模式 西安 观察者模式 规范 视图 视频 解耦器模式 设计 设计原则 设计模式 访问者模式 语法 责任链模式 贪吃蛇 转换 软件工程 软引用 运算符 迭代子模式 适配器模式 选择器 通信 通道 配置 锐化 错误 键盘 闭包 降噪 面向对象 项目构建 黑洞
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×