美文网首页
Gradle通关系列(三)-深入Project

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

作者: kevin丶xie | 来源:发表于2021-02-10 23:27 被阅读0次

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

    没错,赶紧上车...

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

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

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

    相关文章

      网友评论

          本文标题:Gradle通关系列(三)-深入Project

          本文链接:https://www.haomeiwen.com/subject/gyskxltx.html