Gradle通关系列(三)-深入Project

·  阅读 1048

咋一看标题有点开车嫌疑...

没错,赶紧上车...

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,下面是项目结构以及输出

使用模板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构建整体有一个清晰的认识,整个构建过程其实就是以下几个步骤:

  1. 建立项目结构 - 配置有哪些项目需要参与构建
  2. 配置项目 - 配置Project的实例,做一些属性配置(properties、extensions、conventions、extra等),做一些任务配置(定义项目完成构建需要的一系列任务)
  3. 执行任务,完成构建输出

其实上面三步就是Gradle的三个阶段:初始化阶段、配置阶段、执行阶段

分类:
Android
标签:
分类:
Android
标签:
收藏成功!
已添加到「」, 点击更改