自定义插件

Gradle插件打包可重用的构建逻辑片断,可用于许多不一样的项目和构建。 Gradle容许实现本身的插件,所以能够重用构建逻辑,并与其余人共享。java

可使用任何语言实现Gradle插件,前提是实现最终编译为JVM字节码。 在咱们的示例中,咱们将使用Groovy做为实现语言。 Groovy,Java或Kotlin都是用于实现插件的语言的不错选择,由于Gradle API旨在与这些语言一块儿使用。 一般,使用Java或Kotlin实现的静态类型的插件将比使用Groovy实现的相同插件执行得更好。android

有几个地方能够放置插件的源代码。git

Build script

能够直接在构建脚本中包含插件的源代码。这样作的好处是插件能够自动编译并包含在构建脚本的类路径中,而无需执行任何操做。可是,插件在构建脚本以外是不可见的,所以您没法在其定义的构建脚本以外重用该插件。github

buildSrc project

能够将插件的源代码放在rootProjectDir / buildSrc / src / main / groovy目录(或rootProjectDir / buildSrc / src / main / java或rootProjectDir / buildSrc / src / main / kotlin中。)Gradle将负责编译和测试插件并使其在构建脚本的类路径中可用。 该插件对于构建使用的每一个构建脚本都是可见的。 可是,它在构建以外是不可见的,所以您没法在其定义的构建以外重用该插件。bash

Standalone project

能够为插件建立单独的项目。 该项目生成并发布一个JAR,而后您能够在多个版本中使用它并与其余人共享。 一般,此JAR可能包含一些插件,或将多个相关的任务类捆绑到单个库中。 或二者的某种组合。闭包

基于 Build script 编写插件

要建立Gradle插件,须要编写一个实现Plugin接口的类。 当插件应用于项目时,Gradle会建立插件类的实例并调用实例的Plugin.apply()方法。 项目对象做为参数传递,插件可使用它来配置项目。并发

## build.gradle
class GreetingPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.task('hello') {
            doLast {
                println 'Hello from the GreetingPlugin'
            }
        }
    }
}

// Apply the plugin
apply plugin: GreetingPlugin
复制代码
> gradle -q hello
Hello from the GreetingPlugin
复制代码

须要注意的一点是,为应用它的每一个项目建立了一个新的插件实例。 另请注意,Plugin类是泛型类型。 此示例使其接收Project类型做为类型参数。 插件能够改成接收类型为Settings的参数,在这种状况下,插件能够应用于设置脚本或Gradle类型的参数,在这种状况下,插件能够应用于初始化脚本中。app

使插件可配置

大多数插件须要从构建脚本中获取一些配置。执行此操做的一种方法是使用扩展对象。Gradle项目具备关联的ExtensionContainer对象,该对象包含已应用于项目的插件的全部设置和属性。能够经过向此容器添加扩展对象来为插件提供配置。扩展对象只是一个Java Bean兼容类。maven

##build.gradle
class GreetingPluginExtension {
    String message = 'Hello from GreetingPlugin'
}

class GreetingPlugin implements Plugin<Project> {
    void apply(Project project) {
        // Add the 'greeting' extension object
        def extension = project.extensions.create('greeting', GreetingPluginExtension)
        // Add a task that uses configuration from the extension object
        project.task('hello') {
            doLast {
                println extension.message
            }
        }
    }
}

apply plugin: GreetingPlugin

// Configure the extension
greeting.message = 'Hi from Gradle'
复制代码
> gradle -q hello
Hi from Gradle
复制代码

在此示例中,GreetingPluginExtension是一个普通的Groovy / Kotlin对象,其中包含一个名为message的属性。 扩展对象将添加到名称为greeting的插件列表中。 而后,此对象可用做与扩展对象同名的项目属性。ide

一般,您须要在单个插件上指定几个相关属性。 Gradle为每一个扩展对象添加配置块,所以您能够将设置组合在一块儿。

##build.gradle
class GreetingPluginExtension {
    String message
    String greeter
}

class GreetingPlugin implements Plugin<Project> {
    void apply(Project project) {
        def extension = project.extensions.create('greeting', GreetingPluginExtension)
        project.task('hello') {
            doLast {
                println "${extension.message} from ${extension.greeter}"
            }
        }
    }
}

apply plugin: GreetingPlugin

// Configure the extension using a DSL block
greeting {
    message = 'Hi'
    greeter = 'Gradle'
}
复制代码
> gradle -q hello
Hi from Gradle
复制代码

在此示例中,能够在greeting闭包内将多个设置组合在一块儿。 构建脚本(greeting)中闭包块的名称须要与扩展对象名称匹配。 而后,当执行闭包时,扩展对象上的字段将根据标准Groovy闭包委托功能映射到闭包内的变量。

使用自定义任务和插件中的文件

在开发自定义任务和插件时,最好在接受文件位置的输入配置时保持灵活性。 为此,您能够利用Project.file(java.lang.Object)方法尽量晚地将值解析为文件。

## build.gradle
class GreetingToFileTask extends DefaultTask {

    def destination

    File getDestination() {
        project.file(destination)
    }

    @TaskAction
    def greet() {
        def file = getDestination()
        file.parentFile.mkdirs()
        file.write 'Hello!'
    }
}

task greet(type: GreetingToFileTask) {
    destination = { project.greetingFile }
}

task sayGreeting(dependsOn: greet) {
    doLast {
        println file(greetingFile).text
    }
}

ext.greetingFile = "$buildDir/hello.txt"
复制代码
> gradle -q sayGreeting
Hello!
复制代码

在此示例中,咱们将greet任务的destination属性配置为闭包/提供程序,使用Project.file(java.lang.Object)方法对其进行评估,以将闭包/提供程序的返回值转换为最后的File对象。在上面的示例中,咱们在配置为将其用于任务后指定greetingFile属性值。 这种延迟评估是在设置文件属性时接受任何值,而后在读取属性时解析该值的关键优点。

将扩展属性映射到任务属性

经过扩展从构建脚本捕获用户输入并将其映射到自定义任务的输入/输出属性是一种有用的模式。 构建脚本做者仅与扩展名定义的DSL进行交互。 命令式逻辑隐藏在插件实现中。

Gradle提供了一些能够在任务实现和扩展中使用的类型来帮助您完成此任务。

一个独立的项目

如今咱们将把咱们的插件移到一个独立的项目中,这样咱们就能够发布它并与其余人共享。 这个项目只是一个Groovy项目,它生成一个包含插件类的JAR。 这是项目的简单构建脚本。 它应用Groovy插件,并将Gradle API添加为编译时依赖项。

##build.gradle
plugins {
    id 'groovy'
}

dependencies {
    implementation gradleApi()
    implementation localGroovy()
}
复制代码

那么Gradle如何找到插件实现呢? 答案是你须要在jar的META-INF / gradle-plugins目录中提供一个与你的插件的id匹配的属性文件。

示例:为自定义插件接线

src/main/resources/META-INF/gradle-plugins/org.samples.greeting.properties

implementation-class=org.gradle.GreetingPlugin
复制代码

请注意,属性文件名与插件ID匹配,而且放在resources文件夹中,而implementation-class属性标识插件实现类。

建立插件ID

插件ID以相似于Java包的方式(即反向域名)彻底限定。 这有助于避免冲突,并提供了一种对具备相似全部权的插件进行分组的方法。

插件ID应该是反映命名空间(指向您或您的组织的合理指针)的组件的组合,以及它提供的插件的名称。例如,若是您有一个名为“foo”的Github账户,而且您的插件名为“bar”,则合适的插件ID多是com.github.foo.bar。

发布插件到本地

## build.gradle
classpath "com.github.dcendents:android-maven-gradle-plugin:1.5"
复制代码
## java-publish.gradle
apply plugin: 'maven-publish'

def javadocJar = task("javadocJar", type: Jar, dependsOn: javadoc) {
    classifier = 'javadoc'
    from javadoc.destinationDir
}
def sourcesJar = task("sourcesJar", type: Jar) {
    classifier = 'sources'
    from sourceSets.main.java.srcDirs
}

publishing {
    publications {
        Component(MavenPublication) {
            from components.java
            groupId = group
            artifactId = POM_ARTIFACT_ID
            version = version

            artifact sourcesJar
            artifact javadocJar
        }
    }
}

task buildAndPublishToLocalMaven(type: Copy, dependsOn: ['build', 'publishToMavenLocal']) {
    group = POM_NAME

    // save artifacts files to artifacts folder
    from configurations.archives.allArtifacts.files
    into "${rootProject.buildDir}/outputs/artifacts/"
    rename { String fileName ->
        fileName.replace("release.aar", "${version}.aar")
    }

    doLast {
        println "* published to maven local: ${project.group}:${project.name}:${project.version}"
    }
}
复制代码
## gradle.properties
POM_ARTIFACT_ID=greeting-gradle-plugin
POM_NAME=greeting
POM_PACKAGING=jar
复制代码

点击以后会在本地仓库生成对应的jar包:

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

找到项目的根目录的build.gradle文件:

buildscript {
    repositories {
        mavenLocal()

        google()
        jcenter()
    }

    dependencies {
        // classpath
        classpath 'com.android.tools.build:gradle:3.2.1'
        classpath("com.zpw.greeting:greeting-gradle-plugin:1.0")
    }
}
复制代码

而后在项目app的build.gradle文件中添加:

apply plugin: 'com.zpw.greeting_plugin'
复制代码

为插件提供配置DSL

可使用扩展对象为插件提供配置。 使用扩展对象还扩展了Gradle DSL,为插件添加项目属性和DSL块。 扩展对象只是一个常规对象,所以您能够经过向扩展对象添加属性和方法来提供嵌套在此块中的DSL元素。

嵌套的DSL元素

当Gradle建立任务或扩展对象时,Gradle会修改实现类以混合DSL支持和可扩展性。 要建立嵌套的DSL元素,可使用ObjectFactory类型建立相似装饰的对象。 而后,能够经过插件扩展的属性和方法使这些装饰对象对DSL可见:

class GreetingPluginExtension {
    String message
}
复制代码
class GreetingPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        def extension = project.extensions.create('greeting', GreetingPluginExtension)

        project.task('hello') {
            doLast {
                println "${extension.message}"
            }
        }
    }
}
复制代码
apply plugin: 'com.zpw.greeting_plugin'
greeting {
    message = 'Hi'
}
复制代码
> gradle -q hello
Hi
复制代码
相关文章
相关标签/搜索