Gradle 插件开发

前言

本文主要梳理下如何开发自定义 Gradle 插件,参考自 Gradle 官网

源码放置

一共有以下几个地方可以放置插件的源代码。

  1. build script

    在构建脚本中直接包含插件的源代码。这样做的好处是插件会自动编译并包含在构建脚本的类路径中,而您不需要做任何事情。然而,插件在构建脚本之外是不可见的,因此不能在定义插件的构建脚本之外重用插件。

  2. buildSrc module

    可以把插件的源代码放在rootProjectDir/buildSrc/src/main/java 目录下,注:如果用 groovy 写就把 java 替换为 groovy ,kotlin 也一样。Gradle 会自动进行编译,并使其在构建脚本的类路径中可用。该插件对构建所使用的每个构建脚本都是可见的。然而,它在构建之外是不可见的,因此不能在定义它的构建之外重用插件。插件 ID 通过 build.gradle 进行配置。

    gradlePlugin {
    plugins {
    androidPackPlugin {
    id = 'com.hefuwei.package'
    implementationClass = 'com.hefuwei.pack.TestPlugin'
    }
    }
    }
  3. standalone module

    可以为你的插件创建一个单独的模块。该模块生成并发布一个 JAR,您可以在多个构建中使用该 JAR并与其他人共享。插件 ID 通过 properties 进行配置。

    # com.android.application.properties 文件名就是插件 ID
    implementation-class=com.android.build.gradle.AppPlugin

在日常开发中 com.android.application、kotlin-android 等插件其实都是采用的第三种,因为前两种无法脱离当前项目,下面来看看如何编写插件。

插件编写

要开发一个 Gradle 插件,需要编写一个类实现 Plugin 接口,当插件被应用到一个项目时,Gradle 会创建一个该类实例,并调用其 apply 方法。下面以一个简单插件为例(代码直接放置 build.gradle 中),该插件逻辑非常简单就添加了一个名为 hello 的 Task。

class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
project.task('hello') {
doLast {
println 'Hello from the GreetingPlugin'
}
}
}
}
// 应用该插件
apply plugin: GreetingPlugin

配置好以后就可以在命令行中执行 gradle -q hello ,输出内容如下:

> gradle -q hello
Hello from the GreetingPlugin

注意:Plugin 是一个泛型类,泛型类型除了 Project 以外,还可以是 Settings 以及 Gradle,其中前者可以在 settings.gradle 中被应用,后者可以在 init.gradle 中被应用,不过这两种使用场景还是比较罕见的。

插件配置

大多数插件都提供了配置项,比如 Android 构建插件 com.android.application 提供了以下配置项:

android {
compileSdkVersion 30
defaultConfig {
applicationId "com.hefuwei.gradletest"
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

那么这个是如何做到的?其实很简单 Project 实例关联了一个 ExtensionContainer 实例,我们只需要写一个 JavaBean 类并添加到该容器中即可。下面为一个简单示例,其允许用户配置问候语。

class GreetingPluginExtension {
String message = 'Hello from GreetingPlugin'
}
class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
// 创建并添加扩展到 ExtensionContainer 中,并制定扩展名为 greeting。
def extension = project.extensions.create('greeting', GreetingPluginExtension)
project.task('hello') {
doLast {
println extension.message
}
}
}
}
apply plugin: GreetingPlugin
// 配置扩展
greeting {
message 'Hi from Gradle'
}

配置好以后再次在命令行中执行 gradle -q hello ,输出内容如下:

> gradle -q hello
Hi from Gradle

插件扩展原理就是当 build.gradle 中使用了扩展名时 (本例中为 greeting )Gradle 就会创建扩展类(本例中未 GreetingPluginExtension)实例,然后执行闭包或者赋值操作。最后插件内部就可以获取到配置的内容(需要到项目配置完毕后才能取到值因为插件应用阶段项目还没配置结束)。

插件发布

要发布插件那么只能把插件代码放到一个单独模块中去,然后在其 build.gradle 文件中应用 java-gradle-plugin 插件,这会应用 java 插件、添加 gradleApi 依赖以及自动生成 xxx.properties 文件(再也不用去记该把该文件放到哪里了)。同时还需要应用 maven 插件,添加 uploadArchives 这个 Task 其可以让我们把插件上传到 maven 仓库上去共享。

plugins {
id 'java-gradle-plugin'
id 'maven'
}
gradlePlugin {
plugins {
plugin1 {
id = 'com.hefuwei.test1'
implementationClass = 'com.hefuwei.Test1'
}
plugin2 {
id = 'com.hefuwei.test2'
implementationClass = 'com.hefuwei.Test2'
}
}
}
uploadArchives {
repositories {
mavenDeployer {
pom.groupId = 'com.hefuwei'
pom.artifactId = "pack"
pom.version = '1.0.0'
repository(url: URL) {
authentication(userName: USERNAME, password: PASSWORD)
}
}
}
}

配置完毕后,直接执行 gradle {moduleName}: uploadArchives 即可上传到 maven 仓库。

应用远程插件

要想应用远程插件,首先得知道其在哪个仓库中,同时得了解其代码库名,以及插件 Id。配置项目级 build.gradle 文件配置插件仓库其代码库名。

buildscript {
repositories {
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'
}
}

上述代码表示从 google 仓库中拉取 com.android.tools.build.gradle 代码库。同时在模块级 build.gradle 中应用指定插件。

plugins {
id 'com.android.application'
}

完成上述配置后,Gradle 就会自动拉取代码库,并找到指定插件类并应用。

0%