Gradle入门
Contents
前言
在前一篇文章我们讲了 Groovy ,有了 Groovy 的基础就能看懂 Gradle 里的语法。但是光有 Groovy 基础还是不够的, Gradle 提供了一些 API 让我们可以很方便的参与到项目的构建中。
目录结构
在一个普通的 gradle 项目中通常会包含如下结构
gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat
gradlew
gradlew 其实就是一个脚本文件,用来执行相应的 task(后面会介绍) 。
gradlew 是在 Linux 和 macOS 下使用的,而 gradlew.bat 则是 Windows 下的批处理文件,在 Windows 下使用。
gradlew 是和特定的版本关联在一起的,当我们有多个版本的 gralde 的时候,这样可以保证我们的项目不会因为版本的问题导致编译不了。如果关联的版本不存在, gralde 会先下载。
wrapper
gradle-wrapper.jar
gradle-wrapper.jar 是一个用来执行下载特定版本 gralde 的 jar 包
gradle-wrapper.properties
gradle-wrapper.properties 文件中存放了特定版本的 Gradle 的下载路径,以及本地下载好的路径。
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
生命周期
在 Gradle 中会在不同阶段做不同事情,也就是 Gradle 有自己的生命周期,分为初始化、配置、执行。
初始化阶段
对于 Android 来说,初始化阶段就是加载 settings.gralde 看看引入了哪些项目,对于引入的项目都会为其创建一个 Project 对象。
配置阶段
在配置阶段会执行每个项目下的 build.gradle 文件,根据项目的依赖生成拓补图。
执行阶段
在执行阶段会执行特定的 Task ,在这个阶段是真正干活的,会执行 Task 具体的逻辑。
生命周期的监听
在 gralde 执行的过程中,我们可以通过对其生命周期进行监听,方便我们在特定的时期做一些逻辑处理。
执行 gralde 任务会自动执行初始化和配置。在这个过程中我们可以对生命周期进行监听。
// 初始化阶段完成的回调
this.beforeEvaluate {
println "初始化完成"
}
// 配置阶段完成后的回调
this.afterEvaluate {
println "配置完成"
}
// gradle 执行完毕后的监听回调
this.gradle.buildFinished {
println "任务执行完成"
}
Project
前面提到在 settings.gralde 中使用 include 关键字引入的项目都会创建一个 project 。 gralde 为我们提供了许多 API 来操作 project 。
获取所有 Project
// 获取所有 project
def projects = getAllprojects()
projects.each {
println "Project name is: ${it.name}"
}
输出如下所示
Project name is: Gradle
Project name is: app
Project name is: groovy
可以看到当前工程下有三个 Project 。其实在项目的 build.gralde 也有对所有项目进行配置的相关代码,来看一下
allprojects {
repositories {
google()
jcenter()
}
}
在这里为所有的项目都配置了仓库,这样我们依赖第三方的项目才知道要到哪里去下载。
这里可以直接使用 allprojects 是因为 groovy 会为默认为字段加上 getter/setter 。
获取子 Project
subprojects.each {
println "sub project name is: ${it.name}"
}
输出结果如下
sub project name is: app
sub project name is: groovy
可以看到比之前少了 Gradle 的 Project ,这是因为 Gradle 是 Root Project 。
获取父 Project
subprojects.each {
println "the sub project ${it.name} parent name is: ${it.parent.name}"
}
输出结果如下
the sub project app parent name is: Gradle
the sub project groovy parent name is: Gradle
可以看到 app 和 groovy 的 parent 都是 Gradle 。如果当前项目时根项目的话会返回 null 。
获取 Root Project
println "the root project name is: ${rootProject.name}"
输出结果如下
the root project name is: Gradle
获取指定的 Project
project('app') {
println "current project name is: ${it.name}"
}
输出结果如下
current project name is: app
通过指定 project 的名字我们就可以获取指定的 Project 。
扩展属性
在 Project 中为我们定义了有些属性,但是这些属性太少了,我们不够用,所以 Gradle 考虑到这个问题了,为我们提供了 ext 字段,让我们可以去扩充需要的属性。我们以 compileSdkVersion 为例演示一下怎么使用。
我们在项目下新建一个 config.gralde 文件,内容如下
ext {
android = [
compileSdkVersion: 29
]
}
然后我们就可以在别的模块中使用了,比如在 app 模块的 build.config 中可以这么用
apply plugin: 'com.android.application'
apply from: "config.gradle"
android {
compileSdkVersion rootProject.ext.android["compileSdkVersion"]
}
这样如果我们有很多模块,就可以统一配置为一个,避免了硬编码。这样不会因为要升级 sdk 的版本,把所有的模块都改一遍。
除了可以在 gralde 文件中设置,还可以在 gralde.properties 中设置,不过在 gralde.properties 中设置的类型需要强制转换成需要的类型。
compileSdkVersion=29
在使用的时候可以通过 hasProperty('compileSdkVersion') 来判断是否有这个属性,有的话可以通过 compileSdkVersion.toInteger 来把类型装换为需要的类型。
文件操作
// 获取根路径
println "the root dir is: ${rootDir}"
// 获取项目路径
println "the project dir is: ${projectDir}"
// 获取 build 路径
println "the build dir is: ${buildDir}"
输出结果如下
the root dir is: /Users/devbins/Desktop/Gradle
the project dir is: /Users/devbins/Desktop/Gradle
the build dir is: /Users/devbins/Desktop/Gradle/build
拷贝文件
copy {
from file('build.gralde')
into buildDir
}
通过 copy 闭包实现拷贝文件非常方便
Task
在之前我们介绍了 Gradle 生命周期,提到了 Task 会在执行阶段运行,现在就来看看。
定义 Task
task gradle {
println 'hello gradle'
doLast {
println 'do last'
}
doFirst {
println 'do first'
}
}
在 Task 中,除了在 doLast 和 doFirst 中的代码,其余的代码都是在配置阶段执行的。
除了上面这种方式用来定义 Task ,下面这几种也是可以的
task task1(group: "gradle", "description": "gradle1 task") {
println 'a gradle task'
}
this.tasks.create(name: 'task2', group:"gradle") {
println "gradle2"
}
// 方法一
task task3(dependsOn: [task1, task2]) {
setGroup("gradle")
setDescription("gradle3 task")
}
Task 依赖
Gradle 中有非常多 Task ,有些需要在某一个 Task 执行之后再执行特定的 Task ,这样就会形成一个依赖,我们可以通过手动来指定这些依赖。
// 方法一
task task4(dependsOn: [task1, task2]) {
dependsOn task1
}
// 方法二
task4.dependsOn(task1,task5)
执行顺序
除了上面依赖的方式可以决定 Task 的调用顺序,还可以通过 mustRunAfter 来设置调用的顺序
task task5 {
doLast {
println 'task5'
}
}
task task6 {
mustRunAfter "task5"
doLast {
println 'task6'
}
}
总结
今天我们了解了 Gradle 的目录结构、生命周期、 Project 还有创建 Task ,有了这些基础后,就不会再认为 Gradle 只是个配置文件了。
我们可以根据自己的需要去改进项目的构建。