Gradle通关系列(三)-深入Project
咋一看标题有点开车嫌疑...
没错,赶紧上车...
Project接口
Project接口中包含了你主要与构建交互的api,这些api你可以直接在gradle脚本中使用。每一个Project对象与build.gradle构建脚本是一对一的关系,Gradle为每个项目都创建了一个Project对象用来参与构建,步骤如下:
- 为构建创建Settings实例
- 解析settings.gradle脚本,如果存在,就针对Settings对象来配置它
- 用配置好的Settings对象创建Project实例结构
- 最后解析每个项目的build.gradle脚本,来配置它的Project实例
Tasks
项目本质上是Task对象的集合。每个task执行一些基本的工作,例如编译类,或运行单元测试,或压缩WAR文件。 可以使用TaskContainer上的create()方法之一将任务添加到项目中,并对其操作
Dependencies
一个项目为了完成它的工作通常会有很多依赖项。同样,一个项目通常会产生许多其他项目可以使用的artifact。这些依赖项在configuration中分组,可以从repository中检出和上传,可以通过getConfigurations()方法返回的ConfigurationContainer来管理configurations,通过getDependencies()方法返回的DependencyHandler来管理dependencies,通过getArtifacts()方法返回的ArtifactHandler 来管理artifacts,通过getRepositories()方法返回的RepositoryHandler来管理repositories。
Properties
以下内容都可以被看作成Project的属性
- Project自身的属性以及方法
- extra属性
- Extension
- Convention
- Task
- 从父项目中集成来的extra、convention属性
可以通过Object property(String propertyName)方法获取会按以上流程检索属性值
从自定义构建理解Project
我们在第一篇了解到一个很重要的点,每一个Gradle构建都是由一个或多个Project组成,Project代表的取决于你想用Gradle让他做什么 。Project又是一系列task的集合。
假如一个Project需要打包指定路径下的资源,并输出为zip包,这就是我们需要Gradle为我们做的
直接约定路径,将文件打包,输出zip
import org.gradle.kotlin.dsl.support.zipTo
task("zipRes") {
group = "output"
doLast {
val resPath = "src/res"
val file = file(resPath)
zipTo(file("output.zip"), file)
}
}
执行zipRes task,将会完成输出
WX20210210-233126.png
使用模板task
向一些常规的copy,压缩操作,Gradle都有内置的模板task,我们可以直接使用内置的模板task
tasks.register<Zip>("zipRes") {
group = "output"
from("src/res")
this.destinationDir = file("./")
this.archiveName = "output.zip"
this.archiveExtension.set("zip")
}
拓展Task配置
我们上面使用的资源路径是写死的,我们需要将他弄成配置项
import org.gradle.kotlin.dsl.support.zipTo
//创建自定义的ZipRes Task,将配置作为task的属性
open class ZipResTask : DefaultTask() {
var resPath: String = "src/res"
var outputPath: String = "output.zip"
//task的执行任务
@TaskAction
fun zipRes() {
println(project.name)
println(resPath)
println(outputPath)
val resPath = resPath
val resFile = project.file(resPath)
val zipFile = project.file(outputPath)
zipTo(zipFile, resFile)
}
}
//注册任务
tasks.register("zipRes", ZipResTask::class) {
//配置任务
resPath = "resSrc"
outputPath = "resOutput.zip"
}
这样我们在注册task时就可以配置这两个参数
构建拓展成插件
现在由于很多项目都需要使用这样构建,我们需要将他做成插件的形式
我们把上面的构建内容写到custom_build.gradle.kts文件中,并在build.gradle.kts中进行依赖
apply(from = "custom_build.gradle.kts")
这样一来其他项目依赖这个脚本就能自动实现上述构建逻辑了,咦,不对又不能配置了,难道我要自己创建task然后去配置resPath、outputPath属性么
拓展Project的配置
//custom_build.gradle.kts
import org.gradle.kotlin.dsl.support.zipTo
open class ZipResExtensions {
var resPath: String = ""
var outputPath: String = ""
}
extensions.create<ZipResExtensions>("zipRes")
open class ZipResTask : DefaultTask() {
@TaskAction
fun zipRes() {
val zipResExtensions = project.extensions.getByName<ZipResExtensions>("zipRes")
val resPath = zipResExtensions.resPath
val file = project.file(resPath)
zipTo(project.file(zipResExtensions.outputPath), file)
}
}
tasks.register("zipRes", ZipResTask::class)
apply(from = "custom_build.gradle.kts")
//此处由于Kotlin静态强类型语言,需要处理依赖关系,使用反射去配置值
extensions.configure<Any>("zipRes") {
val resPathSetter = this.javaClass.getMethod("setResPath", String::class.java)
resPathSetter.invoke(this, "resSrc")
val outputPathSetter = this.javaClass.getMethod("setOutputPath", String::class.java)
outputPathSetter.invoke(this, "resOutput.zip")
}
如果使用groovy的话代码就相当简单了
apply 'from': 'custom.gradle'
zipRes {
resPath = 'resSrc'
outputPath = 'resOutput.zip'
}
上传输出文件
项目构建的输出现在需要上传,我们添加一个上传的task
//custom_build.gradle.kts
import org.gradle.kotlin.dsl.support.zipTo
open class ZipResExtensions {
var resPath: String = ""
var outputPath: String = ""
}
extensions.create<ZipResExtensions>("zipRes")
open class ZipResTask : DefaultTask() {
@TaskAction
fun zipRes() {
val zipResExtensions = project.extensions.getByName<ZipResExtensions>("zipRes")
val resPath = zipResExtensions.resPath
val file = project.file(resPath)
zipTo(project.file(zipResExtensions.outputPath), file)
}
}
//创建配置项
configurations {
create("zipResRelease")
}
//为配置定义artifact
afterEvaluate {
artifacts {
val zipResExtensions = project.extensions.getByName<ZipResExtensions>("zipRes")
add("zipResRelease", project.file(zipResExtensions.outputPath))
}
}
val zipRes = tasks.register("zipRes", ZipResTask::class)
tasks.register("uploadOutput", Upload::class) {
dependsOn(":zipRes")
repositories {
flatDir {
dir("uploadDir")
}
}
configuration = configurations["zipResRelease"]
}
执行uploadOutput命令,完成zipRes并上传
总结
以上的例子主要是为了对Gradle构建整体有一个清晰的认识,整个构建过程其实就是以下几个步骤:
- 建立项目结构 - 配置有哪些项目需要参与构建
- 配置项目 - 配置Project的实例,做一些属性配置(properties、extensions、conventions、extra等),做一些任务配置(定义项目完成构建需要的一系列任务)
- 执行任务,完成构建输出
其实上面三步就是Gradle的三个阶段:初始化阶段、配置阶段、执行阶段