一、安装环境
Gradle 是一种开源自动化构建工具,支持多语言环境,吸收 Ant、Maven 相关思想,同时规避 Ant 的不规范和 Maven 的复杂配置方式以及多种限制的生命周期,并且支持 DSL(领域特定语言,如Groovy)编写构建,这使得脚本更加灵活精悍。
本文以 Gradle 7 为例,需要如下SDK:
JDK 的安装本文不再叙述; 这里要说明的是官网下载的 Gradle 有不同的后缀,其内容也有所不同:
- all.zip : 完整版,包含可执行程序、源代码文件和离线文档
- bin.zip : 可执行程序版,仅包含可执行程序
- src.zip : 源码版,仅包含了 Gradle 的源码,不能用来编译工程
因此如果只是为了编译工程,可以选可执行程序版本这样就少了几十兆大小,如 gradle-7.2-bin.zip
接下来将下载好的压缩包放在自定义的目录下并解压,将其中的 bin 目录在 bashrc 中配置环境变量即可:
# vim ~/.bashrc |
配置完成之后,再终端上验证一下看是否成功:
$ gradle -v |
二、创建 Gradle 项目
Gradle 环境安装好之后,接下来创建一个 Gradle 项目演示其他的内容,Gradle 中提供了初始化项目目录的命令 init,这使得我们不用手工来创建 build.gradle 文件和其他的源代码目录:
# 创建一个空目录 gradleTest,进入 gradleTest 目录后执行init指令 |
这里需要说明的是不同的 Gradle 所能支持创建的项目类型都有所不同,这里采用 Gradle 7 有如下四种类型:
- basic : 缺省值,仅仅创建简单的 settings 和 build 文件
- application : 构建 Java 应用程序
- library : 构建 Java 库
- Gradle plugin : 构建 Gradle 插件
这样跟着提示,依次配置项目类型、使用的语言、脚本语言、包名等,这里我以 basic 为例:
$ gradle init |
这样就得到如下的内容:
build.gradle gradle gradlew gradlew.bat settings.gradle |
三、Gradle 结构类型简介
在学习怎样使用 Gradle 脚本之前,我们先对 Gradle 的重要结构及类型有一个简要了解,下图是根据 Gradle 7.2 版本的 官网 介绍总结:
在上图中看似分了很多内容,其实主要划分为两类:构建脚本模块 和 对象类型; 构建脚本模块中包含不同的块,每个块都有其特定的用途和上下文。这些块定义了构建过程中不同阶段的行为和配置;至于图中的核心类型、发布类型、容器类型等都是 Gradle 中定义的一个个对象,都包含各自的成员变量或作属性、函数、脚本块等,这些对象根据各自的功能划分为一类。接下来对图中几个最重要也是最常用的核心对象类型来做说明。
3.1 Gradle 对象类型
Gradle 对象是在项目初始化时构建,全局单例,只有一个对象,按照主要功能划分如下,更多见官网Gradle:
3.2 Project 对象类型
Project 是与 Gradle 交互的主接口。它提供了 Gradle 各个能力的入口。android 开发中最为我们所熟悉的就是 build.gradle 文件,这个文件与 Project 是一对一的关系,build.gradle 文件是 project 对象的委托。Gradle 构建进程启动的时候会根据 build.gradle 去实例化 Project 类。即构建时,每个 build.gradle 文件会生成一个 Project 对象,这个对象负责当前 module 的构建,主要内容如下所示,更多见官网Project;
3.3 Settings 对象类型
因为 Gradle 的初始化阶段和 settings.gradle 文件息息相关,而 settings.gradle 文件又和 Settings 对象一一对应。Settings 接口类的定义如下,更多见官网Settings:
3.4 Task 对象类型
任务 是 gradle 的最小执行单元,一个 build.gradle 是由一系列的 Task 组成,Task 可以使用 TaskContainer 类的各种方法来创建和查找 task 实例(可以是 Gradle 内置类的实例,也可以是我们自定义 task 类的实例),其主要核心内容如下图所示,更多见官网Task:
3.4.1 Task创建
上面介绍了 Task 的核心内容,那么接下来我们来介绍下如何创建一个 task,创建Task的方式有很多种,但 DefaultTask 是所有任务的基类,因此在创建 Task 时,默认继承 DefaultTask :
//1. 直接声明 |
3.4.2 Task依赖
task之间的依赖关系是通过 task name 来决定的,具体可以分为同项目依赖和跨项目依赖:
task hello { |
跨项目进行task的依赖,如果是跨项目的task依赖的话,需要指定task的路径:
project('zsk-service') { |
3.4.3 条件执行
我们可以给task一些描述信息,这样我们在执行gradle tasks的时候,就可以查看到:
有时候我们需要根据build文件中的某些属性来判断是否执行特定的task,我们可以使用onlyIf :
task hello { |
或者我们可以抛出StopExecutionException异常,如果遇到这个异常,那么task后面的任务将不会被执行:
task compile { |
我们还可以启动和禁用task:
myTask.enabled = false |
3.4.4 任务规则
如果我们想要给某些task定义一些规则,那么可以使用tasks.addRule:
//定义了如下rule,如果taskName是以ping开头的话,那么将会输出对应的内容。 |
3.4.5 任务分组
task分组,我们可以通过 task.group 属性来指定task的分组,没有指明的分组,会默认为 other,这具体可以通过如下命令查看:
gradle tasks --all |
四、扩展属性
Gradle 中的属性分为内置属性和扩展属性,接下来使用一些示例来展示这些属性的用法及特性:
① 内置属性可以直接赋值,无需声明
group = 'com.zsk' |
② 自定义属性可以使用 groovy 语法,也可以与 Java 语法结合
//groovy定义属性 |
4.1 扩展属性及使用
扩展属性使用 ext 来定义:
ext.prop1 = "prop1" |
五、Gradle 的生命周期
Gradle 的核心是一种基于依赖的变成语言,任务与任务之间有一定的依赖关系,并且每个任务只会执行一次。在构建时,Gradle 会将这些任务串联起来形成有向无环图。那么 Gradle 实在什么时候进行串联的呢?这就需要充分了解 Gradle 在各个阶段做了什么事情了,这一过程我们称为生命周期。官网介绍如下:
从上图中可以看到,Gradle 的生命周期分为三个阶段:
1. 初始化阶段: Gradle 支持单项目和多项目构建,在此阶段,Gradle 会解析 setting.gradle 文件,确定哪些项目需要参与构建,并为这些项目创建对应的 Project 实例。
2. 配置阶段: 当完成初始化阶段后,Gradle 会进入配置阶段。配置阶段会解析所有 project 中的 build.gradle 文件获取所有的 task,形成有向无环图后执行依赖关系,并且所有 project 中的build script 部分和 task 的配置阶段都会在这一阶段调用
3. 执行阶段: 当完成任务依赖图之后,Gradle 就做好了一切准备,然后进入执行阶段。按照有向无环图中的 task 列表的顺序,执行所有被指定的 task。
Gradle 在生命周期三个阶段都设置了相应的钩子函数调用:
5.1 初始化阶段
//settings.gradle |
5.2 配置阶段
//settings.gradle |
//project.beforeEvaluate的执行时机 |
5.3 执行阶段
//settings.gradle |
六、Gradle 命令行
与 Gradle 交互有两种方式,一是命令行界面(也即是指令形式),二是IDE的图形界面,如Android Studio,IDE方式固然使用比较方便,可以一则是未必包含所有的指令,其次是在类似 CI/CD 的场景下就不如命令行形式方便,因此掌握基本的命令行指令是非常有必要的。
Gradle 的指令形式定义如下:
gradle [taskName...] [--option-name...] |
- 任务名(taskName)有多个时,使用空格分开,如gradle task1 task2
- 在多项目工程中,执行某个项目的任务时,可以用“:”将项目名添加到任务名之前,如
$ gradle projectName:taskName |
- 可选项(option-name)如果接收参数,建议使用=拼接,如:
$ gradle task1 --console=plain |
- 可选项规定一个行为时,可使用–no-作为其全称(long-form)前缀,来指定它的对立行为。如:
--build-cache |
- 可选项的全称名称常有简写形式 ,如:
--help |
6.1 内建任务指令
Gradle 中内置了一部分任务指令,用于简化构建过程,以下只列举了部分常用指令,更多参见 官网内建任务选项
- gradle build。生成所有的输出,并执行所有的检查。
- gradle run。生成应用程序并执行某些脚本或二进制文件
- gradle check。执行所有检测类任务如tests、linting等
- gradle clean。删除build文件目录。
- gradle projects。查看项目结构。
- gradle tasks。查看任务列表。查看某个任务详细信息,可用gradle help –task someTask
- gradle dependencies。查看依赖列表。
- gradle 任务 –scan。生成一个包含构建执行过程的详细信息,如依赖解析、插件使用、任务执行时间等。并将这个数据发送到Gradle的服务器
6.2 调试类指令
以下仅列举部分,更多详见 官网调试类选项
- -?, -h, –help。查看帮助信息。
- -v, –version。查看版本信息。
- -s, –stacktrace。执行任务时,打印栈信息。如gradle build –s
6.3 日志类指令
以下仅列举部分,更多详见 官网日志类选项
- -q, –quiet。只打印errors类信息。
- -i, –info。打印详细的信息。
6.4 自定义指令
Gradle 也支持扩展自定义指令,详见 Command Line options。
这里需要使用 Option注释,定义格式如下:
@Option(option = "flag", description = "Sets the flag") |
举例来说,自定义任务 UrlVerify 通过进行 HTTP 调用并检查响应代码来验证是否可以解析 URL。要验证的 URL 可通过属性进行配置,属性的 setter 方法使用@Option进行注释:
import org.gradle.api.tasks.options.Option; |
创建一个 UrlVerify 实例:
tasks.register('verifyUrl', UrlVerify) |
执行 verifyUrl 指令:
$ gradle -q verifyUrl --url=http://www.google.com/ |
七、Gradle Wrapper
Gradle Wrapper 称为Gradle包装器,是对Gradle的一层包装,所有使用 gradle 指令的地方都可以使用 Gradle Wrapper 来替换。之所以使用 Gradle Wrapper,原因有如下几点:
- 保持版本一致:确保开发者在构建项目使用相同版本的Gradle,避免版本差异
- 简化安装:对于未安装 Gradle 的开发者,使用 Gradle Wrapper 能在需要时自动下载和配置指定版本的 Gradle 环境
- 便于集成:Gradle Wrapper 非常适合作为 CI/CD 流程中的一部分,因为它可以确保构建环境与开发环境一致
- 简化项目管理:Gradle Wrapper 相关的文件和配置可以随项目一同提交到版本控制系统,方便团队共享
- 提高开发效率:对于新加入项目的开发者,无需担心 Gradle 环境问题,只需执行 Wrapper 提供的脚本即可快速开始构建项目
7.1 构建Gradle Wrapper
在确保计算机中已经配置好 Gradle 环境后,执行如下命令即可生成 Gradle Wrapper 相关的文件和配置:
$ gradle wrapper |
这会在项目根目录下生成如下文件:
├── gradle |
每个文件的含义如下:
- gradle-wrapper.jar :包含Gradle运行时的逻辑代码。
- gradle-wrapper.properties :负责配置包装器运行时行为的属性文件,用来配置使用哪个版本的Gradle等属性。
- gradlew:Linux平台下,用于执行Gralde命令的包装器脚本。
- gradlew.bat:Windows平台下,用于执行Gralde命令的包装器脚本。
当生成好了上面的这些目录与文件后,用户就可以将工程push到远程,当其他用户clone下来后就可以直接进行项目的构建,节省了用户单独下载Gradle的时间,并且可以确保Gradle版本的一致。
7.2 配置Gradle Wrapper
gradle-wrapper.properties 是 Gradle Wrapper的属性文件,用来配置 Gradle Wrapper,Gradle 7.2 版本对应的gradle-wrapper.properties 如下所示
distributionBase=GRADLE_USER_HOME |
字段的含义如下:
- distributionBase:Gradle解包后存储的主目录。
- distributionPath:distributionBase指定目录的子目录。distributionBase+distributionPath就是Gradle解包后的存放位置。
- distributionUrl:Gradle发行版压缩包的下载地址。
- zipStoreBase:Gradle压缩包存储主目录。
- zipStorePath:zipStoreBase指定目录的子目录。zipStoreBase+zipStorePath就是Gradle压缩包的存放位置。
这里我们最需要关注的是distributionUrl这个字段,如果官方的地址下载不了或者缓慢,可以将这个地址换为其他的镜像地址,或者干脆把Gradle发行版压缩包放在服务器上以供下载。