Gradle学习7——编写和使用自定义Task

学习本系列前可以下载相关的github项目gradleLearnDemo
地址:https://github.com/sososeen09/gradleLearnDemo

自定义task包含两个组件:
1)自定义的task类,封装了逻辑行为,也被称作任务类型
2)真实的task,提供了用于配置行为的task类所暴露的属性值。Gradle把这些task称为增强的task。

可维护性是编写自定义task类的优势之一。增强的task的另一个优势是可重用性。自定义task所暴露的属性可以在构建脚本中进行单独设置。

我们还是按照之前的例子,修改配置文件中的release 参数。

1 自定义task类

前面已经提到,Gradle为构建脚本中每个简单的task都创建了一个DefaultTask类型的实例。我们现在创建一个ReleaseVersionTask,它的作用是把目标文件中的release变为true。

class ReleaseVersionTask extends DefaultTask{
  @Input Boolean release
  @OutputFile File destFile

  ReleaseVersionTask(){
    group='versioning'
    description='Makes project a release version.'
  }

  @TaskAction
  void start(){
    project.version.release=true;
    ant.propertyfile(file:destFile){
       entry(key:'release',type:'string',operation:'=',value: 'true')
    }
  }
}

通过org.gradle.api.tasks包下的注解可以用来声明输入输出属性。

task输入验证 @Input注解会在配置期间验证属性值。如果值为null,Gradle会抛出TaskValidationException异常。为了允许输入为null值,可以给它添加@Optional注解。

2 使用自定义task

我们自定义的task类是没有办法自己执行的,要使用和配置自定义task类定义的行为和属性,需要创建一个增强型的task。该task定义了它要使用的task类型,在本例中我们定义一个增强型taskmakeReleaseVersion,它使用的task类型是ReleaseVersionTask,通过为它的属性赋值来设置输入和输出。

task makeReleaseVersion(type:ReleaseVersionTask){
// 设置自定义task属性
    release = version.release
    destFile = versionFile
}

执行 gradle makeReleaseVersion 命令 ,会发现增强型的makeReleaseVersion task与之前的文章中简单的task的运行结果表现完全一致。
与简单的task实现相比,增强型task的一个巨大优势在于所暴露的属性可以被单独赋值。

比如,ProjectVersion 中的release字段名改为了prodReady,属性文件改名为 project-version.properties。
那么makeReleaseVersion task可以这样设置

task makeReleaseVersion(type:ReleaseVersionTask){
    release = version.prodReady
    destFile =file('project-version.properties')
}

3 在buildSrc目录下构建代码

我们可以把ReleaseVersionTask这个类单独放在一个Groovy文件中,这样就可以在其它地方通过导包的方式来重用这个类。
在一个项目工程当中,创建的Groovy类适合被移动到项目的buildSrc目录下。Gradle在buildSrc目录下使源文件结构标准化。Groovy代码放在src/main/groovy目录下,对于Java文件则是放置在src/main/java目录下面。位于这些目录下的文件会被自动编译,并且都加入到Gradle构建脚本的classpath中。

注意:提取一个类到Groovy文件中需要设置package,在build.gradle中或者其它地方使用这个类的时候需要导包,这一点与Java类的使用是一样的。当然了,如果这个类本身就放在build.gradle中则不需要这个过程,就像之前的例子那样。

例如 ReleaseVersionTask

package com.sososeen09.gia

import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
class ReleaseVersionTask extends DefaultTask{
...
}

Groovy文件实际放置的位置是 buildSrc/src/main/groovy/com/sososeen09/gia/ReleaseVersionTask

根据同样的方式,我们也可以把ProjectVersion这个类抽取出来。

使用的时候,在build.gradle中顶部记得导包:

import com.sososeen09.gia.ReleaseVersionTask
import com.sososeen09.gia.ProjectVersion
...

此时,执行gradle makeReleaseVersion 命令,我们就可以看到编译过程:

:buildSrc:compileJava UP-TO-DATE
:buildSrc:compileGroovy UP-TO-DATE
:buildSrc:processResources UP-TO-DATE
:buildSrc:classes UP-TO-DATE
:buildSrc:jar UP-TO-DATE
:buildSrc:assemble UP-TO-DATE
:buildSrc:compileTestJava UP-TO-DATE
:buildSrc:compileTestGroovy UP-TO-DATE
:buildSrc:processTestResources UP-TO-DATE
:buildSrc:testClasses UP-TO-DATE
:buildSrc:test UP-TO-DATE
:buildSrc:check UP-TO-DATE
:buildSrc:build UP-TO-DATE
Reading the version file
:makeReleaseVersion

记住:buildSrc 目录被视为Gradle项目的指定路径。

4 把Task编写的类编译成jar包提供给其它项目使用

我们把Groovy类放在了buildSrc目录下,虽然自定义的Task类与build.gradle分离开了,但是这些类依然只能应用到当前的项目中。如果我们想要在其它的项目中也可以使用这些Task,就需要在单独的项目中来定义,然后其它项目通过声明依赖的方式来使用。

创建一个新项目,把之前我们讲的buildSrc目录下的内容复制到这个项目中。这个时候,我们就要自己使用Groovy插件来编译这些Groovy源代码了,就像我们编译Java代码需要Java插件一样。Groovy插件是基于Java插件的。在这个项目目录下新建一个build.gradle文件,并在文件中引入Groovy Plugin。
还有一点,我们期望把这些Groovy编写的Task和其它类打包成jar文件供其它地方使用。这个时候我们就可以使用maven插件,把jar文件上传到repository中。关于如何使用maven插件上传,可以查阅相关文档,也可以看这篇 Gradle User Guide Maven Plugin。为了简单演示,打包的jar文件上传到了本地的文件系统中。最终的build.gradle文件如下:

apply plugin: 'groovy' 
apply plugin: 'maven'

version = '1.0'
group = 'com.sososeen09.gia'
archivesBaseName = 'releaseVersionTask'

repositories {
    mavenCentral()
}

dependencies {
    // 编译的时候我们需要使用Gradle中的API
    compile gradleApi()
}

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "file:../lib")
        }
    }
}

执行gradle uploadArchives命令后就可以看到,在与当前项目同级的lib文件目录中生成了我们期望的jar文件。

下面来演示如何使用这个jar文件。我们再新建一个工程,这个工程中有一个脚本文件build.gradle和一个配置文件version.properties。
其中,build.gradle中的代码如下:

import com.sososeen09.gia.ReleaseVersionTask
import com.sososeen09.gia.ProjectVersion
buildscript {
    repositories {
        maven {
            url 'file:../lib'
        }

    }

    dependencies {
        classpath 'com.sososeen09.gia:releaseVersionTask:1.0'
    }
}

version=new ProjectVersion(0,1)

task printVersion {
  doLast{
    logger.quiet "Version: $version"
  }
}

// Project接口提供了file方法,它会创建一个相对于项目目录的java.io.File实例
ext.versionFile=file('version.properties')

task loadVersion{
    project.version=readVersion()
}

//readVersion方法,与task是不同的
ProjectVersion readVersion(){
    logger.quiet 'Reading the version file'
    if(!versionFile.exists()){
        throw new GradleException ("Required version file dose not exist:$versionFile.canonicalPath " )
    }

    //Groovy的文件实现通过添加新的方法来读取InputStream
    Properties versionProps=new Properties()
    versionFile.withInputStream{stream->
        versionProps.load(stream)
    }
    // 在Groovy中,如果return是方法中的最后一条语句的话,则可以将它省略
    new ProjectVersion(versionProps.major.toInteger(),versionProps.minor.toInteger(),versionProps.release.toBoolean())
}


task makeReleaseVersion(type:ReleaseVersionTask){
    release = version.release
    destFile = versionFile
}

version.properties中的内容如下:

major=0
minor=1
release=fasle

执行 gradle makeReleaseVersion 命令之后可以看到配置文件中release变为true。

5 总结

通过以上的介绍,我们了解了自定义Task的方式。 自定义的Task可以放置在build.gradle脚本中,也可以在当前的项目的buildSrc目录下。当然了,如果你期望你写的自定义Task可以被其它的项目中使用,那么你可以用一个单独的工程来放置自定的Task。

关于自定义Task的学习,我们也可以查看Gradle的官方Guide来查看如何自定义task

下一篇,我们开始学习Gradle中的依赖管理。

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 这篇文章讲给大家带来gradle打包系列中的高级用法-自己动手编写gradle插件。我们平常在做安卓开发时,都会在...
    呆萌狗和求疵喵阅读 15,910评论 22 80
  • 1. 概述 Android项目的构建过程是由Gradle插件完成的,Gradle 插件是在Gradle框架的基础上...
    耳东CY阅读 8,055评论 1 42
  • 导语: 随着技术的发展,不管是前端开发、服务端开发或者是移动端开发(移动也是前端的一个分支)中都会用到自动化构建工...
    伊始雨深阅读 2,945评论 0 4
  • 多久没有安静下来,记录这自己的内心。一切都是安安静静、如此淡然。 也许是忘性大,也许是没有心,总是这...
    卢新莎子阅读 244评论 0 0