Gradle核心思想(六)自定义Gradle插件的三种方式

本文首发于微信公众号「刘望舒」

相关文章
Gradle核心思想(一)为什么现在要用Gradle?
Gradle核心思想(二)Gradle入门前奏
Gradle核心思想(三)Groovy快速入门指南
Gradle核心思想(四)看似无用,实则重要的Gradle Wrapper
Gradle核心思想(五)通俗易懂的Gradle插件讲解

前言

在上一篇文章Gradle核心思想(五)通俗易懂的Gradle插件讲解中,我介绍了什么是Gradle插件、如何使用Gradle插件、Gradle插件的作用和好处,由于篇幅的原因,还有一个重要的知识点没有讲,那就是自定义Gradle插件(自定义Gradle对象插件)。自定义Gradle插件主要有三种方式,分别是build.gradle中编写、buildSrc工程项目中编写、独立项目中编写。建议阅读本文前,先阅读开头列出的本系列相关文章。

1.build.gradle

对象插件是实现了org.gradle.api.plugins接口的插件,这个接口中只定义个一个简单的apply方法,想要实现自定义插件就需要去实现org.gradle.api.plugins接口。
Groovy、Java、Kotlin都可以作为实现插件的语言,在本文的示例中,使用Groovy作为实现语言。
在实际工作中我们很少会在build.gradle中编写自定义插件,这里是为了带大家写个最简单的例子,可以最快最直接的了解什么是自定义插件。

1.1 简单的自定义插件

这里使用IntelliJ来编辑(AS也可以),首先新建一个Groovy工程:
VZzPjP.png

定义项目的GroupId和ArtifactId:
VZzPjP.png

build.gradle

apply plugin:CustomPlugin
class CustomPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        project.task('CustomPluginTask') {
            doLast {
                println "自定义插件"
            }
        }
    }
}

在build.gradle中自定义了一个插件CustomPlugin,在apply方法中创建一个名称为CustomPluginTask的任务。在IntelliJ的Terminal中输入gradlew.bat CustomPluginTask来执行CustomPluginTask任务。
VZzAHS.png

1.2 自定义插件扩展

再举一个简单的插件拓展例子,通过插件拓展来配置CustomPluginTask的输出字符串,如下所示。
build.gradle

class CustomPluginPluginExtension {
    String message = 'from CustomPlugin'
}
class CustomPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        def extension = project.extensions.create('custom', CustomPluginPluginExtension)//1
        project.task('CustomPluginTask') {
            doLast {
                println extension.message
            }
        }
    }
}
apply plugin: CustomPlugin
custom.message = "自定义插件拓展"//2

CustomPluginPluginExtension类中定义了message变量,CustomPluginPluginExtension是一个Groovy Bean(类似于JavaBean)。注释1处用于添加拓展插件CustomPluginPluginExtension到插件列表中,名称为custom。注释2处设置CustomPluginPluginExtension的message值。
Terminal中输入gradlew.bat CustomPluginTask来执行CustomPluginTask任务。
VZzp9A.png

2.buildSrc工程项目

除了在build.gradle中编写的自定义插件,还可以将插件的源代码放在rootProjectDir/buildSrc/src/main/groovy目录中,Gradle会自动识别来完成编译和测试。
在第一节的工程根目录下建立/buildSrc/src/main/groovy目录,如下图所示。
VZz91I.png
在groovy目录中创建一个groovy文件,比如我的是CustomPlugin.groovy:
buildSrc/src/main/groovy/CustomPlugin.groovy

import org.gradle.api.Plugin;
import org.gradle.api.Project;
class CustomPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        project.task('CustomPluginTask') {
            doLast {
                println "自定义插件"
            }
        }
    }
}

修改build.gradle为如下的内容:
build.gradle

apply plugin: CustomPlugin

Terminal中输入gradlew.bat CustomPluginTask来执行CustomPluginTask任务,会打印出我们想要的结果。

3.独立项目

无论是在build.gradle中编写自定义插件,还是buildSrc项目中编写自定义插件,都只能在自己的项目中进行使用。如果想要分享给其他人或者自己用,可以在一个独立的项目中编写插件,这个项目会生成一个包含插件类的JAR文件,有了JAR文件就很容易进行分享了。

3.1 自定义插件

为了和前两种方式进行区分,用IntelliJ新建一个Groovy工程,我的工程名为CustomPluginShare,后面会用到。
配置build.gradle

apply plugin: 'groovy'

dependencies {
    compile gradleApi()
    compile localGroovy()
}

应用Groovy插件,并将Gradle API添加为编译时依赖项,build工程,会在External Libraries中生成三个jar文件:
VZzFnf.png

这样我们可以在非buildSrc工程项目中使用groovy语法和Gradle的api了。
创建自定义插件
在src/main/groovy/ 目录中创建一个包,我的是com.example.plugins,在com.example.plugins创建一个groovy文件:
src/main/groovy/com/example/plugins/CustomPlugin.groovy

package com.example.plugins
import org.gradle.api.Plugin
import org.gradle.api.Project
class CustomPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        project.task('CustomPluginTask') {
            doLast {
                println "自定义插件"
            }
        }
    }
}

配置properties文件
在buildSrc工程项目中,Gradle可以自动的去识别插件,独立项目中的插件是如何被Gradle识别的呢?答案是需要在生成的JAR文件中提供一个属性文件,这个属性文件名要与插件id相匹配。在resources中创建src/main/resources/META-INF/gradle-plugins/com.example.plugins.customplugin.properties,这个属性文件的名称实际就是插件的id。将properties文件的内容改为:

src/main/resources/META-INF/gradle-plugins/com.example.plugins.properties

implementation-class=com.example.plugins.CustomPlugin

implementation-class属性为自定义插件的名称。
上传插件
这里为了方便举例直接将插件上传到本地,如果想要发布到Maven、ivy等仓库,见下面的文档:
https://docs.gradle.org/4.4/userguide/publishing_ivy.html
https://docs.gradle.org/4.4/userguide/publishing_maven.html
想要发布到Gradle插件门户上,见下面的文档:
https://docs.gradle.org/4.4/userguide/plugins.html#sec:plugins_block
在build.gradle文件中添加如下内容:

apply plugin: 'maven'
group = 'com.example.plugins'
version = '1.0.0'
uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: uri('../repo'))
        }
    }
}

这段代码会将生成的插件上传到项目的平级目录repo下。定义了group和version的名称,这些值会在其他项目依赖该插件时用到。我们Build后会在Gradle窗口中看到uploadArchives,如下图所示。
VZzFnf.png
点击uploadArchives会在本地生成插件相关的文件,比如我的目录和文件如下图所示。
VZzZNQ.png
图中的CustomPluginShare-1.0.0.rar就是我们需要的插件jar包。

3.2 在另一个项目中使用插件

新建一个Groovy项目,我取名为Projet,build.gradle的代码如下:

apply plugin: 'com.example.plugins.customplugin'

buildscript {
    repositories {
        maven {
            url uri('../repo')
        }
    }
    dependencies {
        classpath 'com.example.plugins:CustomPluginShare:1.0.0'
    }
}

其中com.example.plugins是group,CustomPluginShare是自定义插件的名称,1.0.0是版本号,也可以这么写:

dependencies {
     classpath group: 'com.example.plugins', name: 'CustomPluginShare',
             version: '1.0.0'
 }

Terminal中输入gradlew.bat CustomPluginTask来执行CustomPluginTask任务,大功告成。
如果我们将自定义插件发布到Gradle插件门户上,就可以使用插件DSL了:
build.gradle

plugins {
    id 'com.example.plugins.customplugin' version '1.0.0'
}

虽然讲解独立项目的例子超级简单,但我还是将代码上传到GitHub上了,也许会有同学用的上:
https://github.com/henrymorgen/CustomPlugin

总结

本篇文章介绍了自定义Gradle插件的3种方式,旨在以最简单的例子来让大家快速掌握,如果还想了解复杂的自定义插件可以去查看一些开源的Gradle插件,或者在工作中去实践。本篇文章也为学习Android Gradle插件打下了伏笔。

分享到 评论

分享大前端、Java、Android、 跨平台等技术,关注职业发展和行业动态。

---