Gradle之Gradle扩展-自定义插件以及发布

通常我们会想要将一个非常有用的task共享给多个项目使用,Gradle插件正可以解决这一问题。Gradle插件是非常强大的,如Java插件,一行代码:apply plugin: 'java',就可以使用Java插件实现代码的编译、测试和打包成JAR文件;在android中,我们经常使用:apply plugin: 'com.android.application'来加载android插件。

1、首先看一下项目的结构

这里写图片描述

从上到下介绍目录:plugin和project是两个根项目,分别用来发布插件和测试使用插件。plugin项目中的代码默认放在groovy目录下,自定义的插件和task代码都要放到该目录下的包中,resources/META-INF/gradle-plugins目录下放置的是插件的配置文件,如HelloChenPlugin.properties文件暴露了插件的名字叫做HelloChenPlugin,在这个配置文件中将插件的全限定名赋值给键implementation-class

implementation-class=com.chen.plugins.BuildPlugin

project项目用来测试自定义插件的使用,包含了一个model子项目,和普通android工程项目结构是一样的。

2、插件的自定义(plugin工程)
①编写插件文件:编写一个插件要实现org.gradle.api. Plugin< Project >接口,该接口只提供了一个方法:void apply(Project project);。在com.chen.plugins包下新建BuildPlugin.groovy文件,代码如下,插件扩展机制,可以让我们在闭包中为task所需的属性赋值,在后面的使用扩展的时候会看到它的作用,BuildPluginExtension类和BuildTasksParam是两个实体类。

class BuildPlugin implements Plugin<Project> {
    static final String EXTENSION_NAME = 'HelloChen'

    @Override
    void apply(Project project) {
        /**注册一个扩展容器,扩展容器可以使我们在一个闭包中为task赋值*/
        project.extensions.create(EXTENSION_NAME, BuildPluginExtension)
        addTask(project)
    }

    private void addTask(Project project) {
        project.tasks.withType(AbstractTask) {
            /**查找扩展容器中已配置的属性*/
            def extension = project.extensions.findByName(EXTENSION_NAME)
            /**将闭包中的扩展属性值赋给 AbstractTask 的相关属性*/
            conventionMapping.myId = { extension.myId }
            conventionMapping.myName = { extension.myName }
            conventionMapping.myGroup = { extension.myGroup }
        }

        addMyTask(project)
    }

    private void addMyTask(Project project) {
        /**添加一个task,task名字是myTask,定制任务是 MyTask*/
        project.task('myTask', type: MyTask) {
            /**为 MyTask 的myAddress属性赋值*/
            conventionMapping.myAddress = {
                getAddress(project)
            }
        }
    }

    private String getAddress(Project project) {
        /**首先判断project中有没有myAddress(一般在gradle.properties文件中定义)属性,没有则使用配置的属性值*/
        project.hasProperty('myAddress') ? project.myAddress : project.extensions.findByName(EXTENSION_NAME).myAddress
    }
}

②编写task文件:我定义了两个task,一个抽象的task:AbstractTask,一个继承自AbstractTask:MyTask,在com.chen.plugins.tasks包下,代码如下:

abstract class AbstractTask extends DefaultTask {
    /**可以配置的task属性:
     * Gradle 自动为所有属性生成getter和setter方法*/
    @Input
    String myId
    @Input
    String myName
    @Input
    String myGroup

    AbstractTask(String description) {
        this.description = description
        /**指定task的group*/
        group = 'CustomPlugin'
    }

    /**定义一个action*/
    @TaskAction
    void start() {
        BuildTasksParam param = new BuildTasksParam()
        /**直接使用getter方法获取属性值*/
        param.setMyId(getMyId())
        param.setMyName(getMyName())
        param.setMyGroup(getMyGroup())
        try {
            executeAction(param)
        }
        catch (Exception e) {
            logger.error "Failed to execute MyTask ", e
            throw new GradleException(e.message)
        }
    }

    abstract void executeAction(BuildTasksParam param)
}

class MyTask extends AbstractTask {

    @Input
    String myAddress

    MyTask() {
        super('Returns the basic information about an application.')
    }

    @Override
    void executeAction(BuildTasksParam param) {
        /**拿到映射中的赋值,并打印出来*/
        logger.quiet "myId       is    : $param.myId"
        logger.quiet "myName     is    : $param.myName"
        logger.quiet "myGroup    is    : $param.myGroup"
        logger.quiet "myAddress  is    : " + getMyAddress()
    }
}

③配置HelloChenPlugin.properties文件:该文件为插件添加一个短名字,短名字就是文件名,不然每次使用插件都要这样:apply plugin: 'com.chen.plugins.BuildPlugin',配置后只要这样:apply plugin: 'HelloChenPlugin',该配置文件如下,只有一行,为短名字设置真正的插件的全限定名:

implementation-class=com.chen.plugins.BuildPlugin

④构建脚本编写

apply plugin: 'groovy'
/**应用maven插件来发布插件工件*/
apply plugin: 'maven'

/**定义工件的group、name 和 version*/
group = 'com.chen.plugins'
archivesBaseName = 'chen-plugin'
version = '1.0.0'

repositories {
    mavenCentral()
}

dependencies {
    /**定义对groovy和gradle api的依赖*/
    compile localGroovy()
    compile gradleApi()
}

uploadArchives {
    repositories {
        /**配置Maven部署器,将工件上传到本地目录,这里是放到与该项目同级目录的repo目录下*/
        mavenDeployer {
            repository(url: "file://$projectDir/../repo")
        }
    }
}

执行gradle tasks命令,可以看见有一个uploadArchives任务:

这里写图片描述

执行gradle uploadArchives命令发布工件,在项目中多出来一个repo新目录,它包含了插件的JAR文件和POM文件,该目录的结构如下图:

这里写图片描述

3、使用自定义插件(project工程):使用插件就很简单了:
①在根目录的build.gradle构建脚本如下

allprojects {
    group = 'com.chen.app'
    version = '1.0.1'
    buildscript {
        repositories {
            /**指定本地maven仓库*/
            maven { url "file://$projectDir/../../repo" }
            mavenCentral()
        }

        dependencies {
            /**构建脚本并不知道外部插件的存在,除非将插件添加到 classpath*/
            classpath 'com.chen.plugins:chen-plugin:1.0.0'
        }
    }
}

subprojects {
    apply plugin: 'java'
}

②gradle.properties文件配置

myAddress=shanghai

③model子项目的build.gradle构建脚本如下:这里可以看到插件扩展机制的作用,可以直接在HelloChen 扩展中为myTask任务赋值:

/**使用自定义的插件*/
apply plugin: 'HelloChenPlugin'
/**使用 HelloChen 扩展为 myTask 赋值*/
HelloChen {
    myId = 'my id'
    myName = 'hello chen'
    myGroup = 'my group'
    myAddress = 'my address'
}

④执行myTask任务:gradle myTask输出如下,这里可以看到gradle.perproties文件中的属性替换掉了我们在扩展中的值:

> Task :model:myTask 
myId       is    : my id
myName     is    : hello chen
myGroup    is    : my group
myAddress  is    : shanghai

综上就是Gradle自定义插件使用的全部了,在这里只将插件发布到了本地maven,实际中需要发布到服务器实现所有开发者共同使用,只需要修改maven发布和使用时maven仓库的地址即可,当然也可以发布到mavenCentral()。上述代码地址:https://github.com/ChenSWD/CopyGradleInAction/tree/master/chapter08-gradle%E6%8F%92%E4%BB%B6/%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8F%92%E4%BB%B6–%E6%B3%A8%E9%87%8A

猜你喜欢

转载自blog.csdn.net/weixin_38062353/article/details/82731217