学习本系列前可以下载相关的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中的依赖管理。