自定义 Gradle 插件

2021-03-09  本文已影响0人  simplehych

GitHub仓库代码

自定义 Gradle 插件三种方式:

  1. build script
  2. buildSrc
  3. Standalone project 独立 - 本地repo
    3.1. Standalone project 独立 - 远程

方式1: build script

在构建脚本 build.gradle 中直接编写自定义插件的源代码。
好处:可以自动编译并包含在构建脚本的classpath中,不需要再去声明。
不足:这种方式实现的插件在构建脚本之外是不可见的,不能复用。

// 方式一 build script
// 项目根目录下 build.gradle 或者模块下 build.gradle 均可
class GreetingPlugin implements Plugin<Project> {

    @Override
    void apply(Project project) {
        //新建task hello
        project.task('task_hello') {
            doLast {
                println 'Hello from the GreetingPlugin in app'
            }
        }
    }
}
//引入插件
apply plugin: GreetingPlugin

验证:

▶ ./gradlew task_hello

> Task :task_hello
Hello from the GreetingPlugin in root

> Task :app:task_hello
Hello from the GreetingPlugin in app

方式2:buildSrc

该方式完整的目录结构

buildSrc
├──.gradle
├── build
├── build.gradle
└── src
    └── main
        └── groovy
            └── com
                └── buildsrc
                    └── GreetingExtensionPlugin.groovy

操作步骤:

  1. 在工程的根目录下新建 buildSrc 文件夹,rebuild工程 buildSrc 下会生成 .gradle + build 文件。

buildSrc 名字是规定的,不能出错。XXX、buildXXX等其他文件夹rebuild不能生成文件。

  1. 在 buildSrc 文件夹下新建 build.gradle 文件,内容如下
apply plugin: 'groovy'
sourceSets {
    main{
        groovy {
            srcDir 'src/main/groovy'
        }
        resources {
            srcDir 'src/main/resources'
        }
    }
}

//apply plugin: 'java-library'
//sourceSets {
//    main{
//        groovy {
//            srcDir 'src/main/java'
//        }
//        resources {
//            srcDir 'src/main/resources'
//        }
//    }
//}
  1. 依次创建文件夹 buildSrc/src/main/groovy
  2. 创建包名 com/buildsrc ,新建插件代码类
package com.buildsrc

import org.gradle.api.Plugin
import org.gradle.api.Project

class GreetingExtensionPlugin implements Plugin<Project> {

    @Override
    void apply(Project project) {
        // Add the 'greeting' extension object
        def extension = project.extensions.create('greeting', GreetingExtension)

        // Add a task that uses configuration from the extension object
        project.tasks.create('task_buildSrc_greeting') {
            doLast {
                println "${extension.message} from ${extension.greeter}"
                println project.greeting
            }
        }
    }
}

class GreetingExtension {
    String message
    String greeter
}
  1. 在项目或Module的 build.gradle 引入插件
//build.gradle
//引入 1  不import会提示找不到GreetingExtensionPlugin
//import com.buildsrc.GreetingExtensionPlugin 
//apply plugin: GreetingExtensionPlugin
// or 引入 2
apply plugin: com.buildsrc.GreetingExtensionPlugin

greeting {
    message = 'hello'
    greeter = 'GreetingExtensionPlugin'
}
  1. 验证
▶ ./gradlew task_buildSrc_greeting

> Task :app:task_buildSrc_greeting
hello from GreetingExtensionPlugin
extension 'greeting'

扩展属性:自定义插件代码中有一句def extension = project.extensions.create('greeting', GreetingExtension),使用这种方式来给插件代码传递参数。

如果修改代码重新编译报错或不生效,可删除build文件夹重试
存在GreetingExtensionPlugin/GreetingExtension飘红情况提示已经存在,不影响运行

方式3:Standalone project 独立 - 本地repo

上面两种自定义插件都只能在自己的项目中使用,如果想在其他项目中也能复用,可以创建一个单独的项目并把这个项目发布成一个JAR,这样多个项目中就可以引入并共享这个JAR。通常这个JAR包含一些插件,或者将几个相关的task捆绑到一个库中,或者是插件和task的组合, Standalone project创建步骤:

  1. 在Android Studio的rootProject目录下新建一个Module,类型随便选一个就行(如 Android Module),后面会有大的改动。(也可以选择IDEA来开发,IDEA中可以直接创建groovy组件)
  2. 清空Module目录下build.gradle中的所有内容,删除其他所有文件
  3. 在Module中创建src/main/groovy的目录,然后再创建包名文件夹。在main目录下再新建resources/META-INF/gradle-plugins目录,在这个目录下编写一个和插件id名字相同的.properties文件,这样Gradle就可以找到插件实现了。

示例插件功能:新建build目录,并新建个文件写入内容
完成项目目录如下:

├── build.gradle
└── src
    └── main
        ├── groovy
        │   └── com
        │       └── example
        │           └── plugin
        │               └── CustomPlugin.groovy
        └── resources
            └── META-INF
                └── gradle-plugins
                    └── com.example.plugin.properties

  1. 新建AndroidModule,如命名为 CustomPluginModule;清空build.gradle内容,删除其他所有文件
  2. 修改 build.gradle 内容如下:
plugins {
    id 'groovy'
    id 'maven-publish'
    id 'maven'
}

sourceSets {
    main{
        groovy {
            srcDir 'src/main/groovy'
        }
        resources {
            srcDir 'src/main/resources'
        }
    }
}

dependencies {
    implementation gradleApi()
    implementation localGroovy()
}

repositories {
    mavenCentral()
}

group = 'com.example.plugin'
version = '1.0.1-SNAPSHOT'
publishing {
    repositories {
        maven {
            url = uri("$rootDir/repo")
        }
    }
    publications {
        maven(MavenPublication) {
            from components.java
        }
    }
}
  1. 新建 src/main/groovy 目录,在其路径下创建包名目录如 com.example.plugin ,并创建一个名为 CustomPlugin.groovy` 的文件,内容如下:
package com.example.plugin

import org.gradle.api.DefaultTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.TaskAction

class CustomPlugin implements Plugin<Project> {

    @Override
    void apply(Project project) {
        project.tasks.create('writeToFile', CustomPluginTask) {
            destination = { project.greetingFile }
            doLast {
                println project.file(destination).text
            }
        }
    }
}

class CustomPluginTask extends DefaultTask {
    def destination

    File getDestination() {
        //创建路径为destination的file
        project.file(destination)
    }

    @TaskAction
    def greet() {
        def file = getDestination()
        file.parentFile.mkdirs()
        //向文件中写入文本
        file.write('hello world')
    }
}
  1. 创建 resources/META-INF/gradle-plugins 目录,并创建以 Plugin ID 命名的文件 com.example.plugin.properties (与使用相关 apply plugin: 'com.example.plugin' ) 写入如下内容:
// 插件的入口对应的类文件全路径 CustomPlugin.groovy
implementation-class=com.example.plugin.CustomPlugin
  1. 发布该插件到本地项目repo,build.gradle 中的 publishing 任务(注意命令为publish
▶ ./gradlew publish  

或在Android Studio的右上角打开Gradle,执行:plugin分组中的publish命令,执行完成后,会在项目根目录下生成repo仓库。

repo
└── com
    └── example
        └── plugin
            └── custompluginmodule
                ├── 1.0.1-SNAPSHOT
                │   ├── custompluginmodule-1.0.1-20210309.061711-1.jar
                │   ├── custompluginmodule-1.0.1-20210309.061711-1.jar.md5
                │   ├── custompluginmodule-1.0.1-20210309.061711-1.jar.sha1
                │   ├── custompluginmodule-1.0.1-20210309.061711-1.jar.sha256
                │   ├── custompluginmodule-1.0.1-20210309.061711-1.jar.sha512
                │   ├── custompluginmodule-1.0.1-20210309.061711-1.module
                │   ├── custompluginmodule-1.0.1-20210309.061711-1.module.md5
                │   ├── custompluginmodule-1.0.1-20210309.061711-1.module.sha1
                │   ├── custompluginmodule-1.0.1-20210309.061711-1.module.sha256
                │   ├── custompluginmodule-1.0.1-20210309.061711-1.module.sha512
                │   ├── custompluginmodule-1.0.1-20210309.061711-1.pom
                │   ├── custompluginmodule-1.0.1-20210309.061711-1.pom.md5
                │   ├── custompluginmodule-1.0.1-20210309.061711-1.pom.sha1
                │   ├── custompluginmodule-1.0.1-20210309.061711-1.pom.sha256
                │   ├── custompluginmodule-1.0.1-20210309.061711-1.pom.sha512
                │   ├── maven-metadata.xml
                │   ├── maven-metadata.xml.md5
                │   ├── maven-metadata.xml.sha1
                │   ├── maven-metadata.xml.sha256
                │   └── maven-metadata.xml.sha512
                ├── maven-metadata.xml
                ├── maven-metadata.xml.md5
                ├── maven-metadata.xml.sha1
                ├── maven-metadata.xml.sha256
                └── maven-metadata.xml.sha512
  1. 配置插件,在项目的根目录添加classpath和maven对应的本地uri
buildscript {
    repositories {
        google()
        jcenter()
        // 第五步发布的repo路径
        maven {
            url = uri("$rootDir/repo")
        }
    }
    dependencies {
        ...
        classpath "com.example.plugin:custompluginmodule:1.0.1-SNAPSHOT"
    }
}

allprojects {
    ...
}
  1. 引用插件
//方式三  Standalone project
apply plugin: 'com.example.plugin'
ext.greetingFile="$buildDir/hello.txt"
  1. 验证,执行插件任务(CustomPlugin中编写的writeToFile)
▶ ./gradlew writeToFile

> Task :app:writeToFile
hello world

方式3.1:Standalone project 独立 - 发布本地maven

  1. 安装Nexus服务
    Mac可直接使用brew安装
brew install nexus

Windows下载安装 https://www.sonatype.com/nexus/repository-oss-download

  1. 运行Nexus服务
▶ nexus run
        _   __
       / | / /__  _  ____  _______
      /  |/ / _ \| |/_/ / / / ___/
     / /|  /  __/>  </ /_/ (__  )
    /_/ |_/\___/_/|_|\__,_/____/

  Sonatype Nexus (3.30.0-01)

Hit '<tab>' for a list of available commands
and '[cmd] --help' for help on a specific command.
Hit '<ctrl-d>' or 'system:shutdown' to shutdown.
...
-------------------------------------------------
Started Sonatype Nexus OSS 3.30.0-01
-------------------------------------------------

输入system:shutdown 停止服务

  1. 打开Nexus本地仓库地址 http://localhost:8081/ ,点击设置图标
Nexus Repository Mananger
  1. Nexus创建仓库,如plugin-releases
  2. build.gradle 增加上传任务
// 发布-nexus服务maven上传
apply plugin: 'maven'
uploadArchives{
    repositories{
        mavenDeployer{
            //正式发布仓库
            repository(url:"http://localhost:8081/repository/plugin-releases/"){
                authentication(userName:"admin",password:"admin")
            }
            //快照版本的仓库
//            snapshotRepository(url:"http://localhost:8081/repository/plugin-snapshots/"){
//                authentication(userName:"admin",password:"admin")
//            }

            pom.project {
                //版本号,如果是快照版本,其版本号后面应该添加-SNAPSHOT,否则不能正常识别上传
                version '1.0.0'
                //一般写项目名称即可
                artifactId 'customplugin'
                //组别,类似包名,保证唯一性
                groupId 'com.example.pluginhappy'
                //打包格式
                packaging 'aar'
                //描述
                description 'plugin'
            }
        }
    }
}
  1. 执行上传任务
▶ ./gradlew uploadArchives
  1. 项目更路径build.gradle 添加插件配置
buildscript {
    repositories {
       ...
        //方式四  Standalone project - maven仓库 - 配置
        maven {
            url 'http://localhost:8081/repository/plugin-releases/'
        }
    }
    dependencies {
      ...
        //方式四  Standalone project - maven仓库 - 配置
        classpath "com.example.pluginhappy:customplugin:1.0.0"
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

插件的依赖方式 classpatch,类似库的 compile

  1. 引入插件
//方式三、四  Standalone project - 本地repo
// 通过 plugin id 引入插件
apply plugin: 'com.example.plugin'
ext.greetingFile="$buildDir/hello.txt"
  1. 验证
▶ ./gradlew writeToFile   

> Task :writeToFile
hello world

方式3.2:Standalone project 独立 - 发布中央仓库

  1. 注册sonatype账号:【申请上传资格】
    https://issues.sonatype.org/secure/Signup!default.jspa

  2. 登录
    https://issues.sonatype.org/secure/Dashboard.jspa

  3. 新建Issue
    https://issues.sonatype.org/secure/CreateIssue.jspa?issuetype=21&pid=10134

需要审核,Status状态从OPEN变成RESOLVED表示成功!如果中间有问题按Comment提示修改即可

  1. 查看Maven仓库
    https://s01.oss.sonatype.org/#view-repositories
    https://s01.oss.sonatype.org/

  2. 上传

apply plugin: 'maven'
uploadArchives{
    repositories{
        mavenDeployer{
            //正式发布仓库
//            repository(url:"https://s01.oss.sonatype.org/content/repositories/releases/"){
//                authentication(userName:"admin",password:"admin")
//            }
            //快照版本的仓库
            snapshotRepository(url:"https://s01.oss.sonatype.org/content/repositories/snapshots/"){
                authentication(userName:"admin",password:"admin")
            }

            pom.project {
                //版本号,如果是快照版本,其版本号后面应该添加-SNAPSHOT,否则不能正常识别上传
                version '0.0.1-SNAPSHOT'
                //一般写项目名称即可
                artifactId 'customplugin'
                //组别,类似包名,保证唯一性
                groupId 'com.github.simplehych'
                //打包格式
                packaging 'aar'
                //描述
                description 'plugin'
            }
        }
    }
}

执行上传命令

▶ ./gradlew uploadArchives
  1. 使用
buildscript {
    repositories {
        ...
        // 方式五 Standalone project - 中央maven仓库 - 配置
        maven {
            url 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
        }
    }
    dependencies {
        ...
        //方式五  Standalone project - 中央maven仓库 - 配置
        classpath "com.github.simplehych:customplugin:0.0.1-SNAPSHOT"
    }
}

//方式三、四、五  Standalone project - 本地repo
// 通过 plugin id 引入插件
apply plugin: 'com.example.plugin'
ext.greetingFile = "$buildDir/hello.txt"

参考资料

感谢以下文章作者
Gradle官网
Gradle系列之初识Gradle
Gradle理论与实践四:自定义Gradle插件
Maven(6) Java上传本地jar包到maven中央仓库

上一篇下一篇

猜你喜欢

热点阅读