美文网首页
自定义Gradle 插件及遇到的问题

自定义Gradle 插件及遇到的问题

作者: wind_sky | 来源:发表于2019-08-07 16:07 被阅读0次

以自定义一个TestPlugin 的插件为例,记录一下遇到的坑。

一. 自定义Gradle 插件的步骤

1. 创建一个插件的项目

本例是在一个project 里创建一个module,module 名就叫做testplugin。创建完之后,目录结构可能跟plugin 所需的有些不一致,可以先将无用的目录删除掉,然后在main 文件夹下创建groovy 文件用来保存groovy 代码,

同时在main 目录下创建resources 目录,在resource 目录下创建META-INF 目录,在META-INF 目录下创建gradle-plugins 目录,啰嗦了这么多是因为这块有坑。最后形成的文件结构如下图所示:

image.png
:注意箭头所指处,META-INF/gradle-plugins 被简写成了这种样式,这个我们也都明白,但是注意在新建目录时不要直接写成这种 "点" 的形式,因为 "点" 也会被作为目录名而不是下级目录,但是在新建包时是可以直接写点的。

在gradle-plugins 目录下创建xxx.properties 文件,这个文件的意义就是为我们自定义的plugin 声明了id 为xxx。当我们在使用plugin 时会有这样一句:

apply plugin: 'xxx'

上面这句的 xxx 就是plugin 的 id。另外xxx.properties 的内容如下:

implementation-class=com.whx.testplugin.TestPlugin

后面的class 根据自己的实现来改。

2. 配置gradle 文件

上图中的build.gradle 文件,为了能开发插件,需要进行相关配置:

// 应用groovy,plugin 开发是基于groovy 语言的
apply plugin: 'groovy'
// 应用maven,用于将插件上传至maven 仓库
apply plugin: 'maven'

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
}

repositories {
    jcenter()
    mavenCentral()
}

// 定义组,发布plugin 使用
group='com.whx.testPlugin'
// plugin 版本
version='1.0.0'

// 一个将plugin 上传到maven 仓库的Task
uploadArchives {
    repositories {
        mavenDeployer {
            // 定义插件打包后上传的位置,可以随意指定,但是在使用时需要指定同样的文件才能找到
            // 这里指定的是本地相对路径
            repository(url: uri('../repo'))
        }
    }
}

dependencies {
    compile gradleApi()     // groovy API
    compile localGroovy()   // groovy API
    compile 'com.android.tools.build:gradle:3.0.0'      // 如果Android 编译相关,需依赖这个
}

配置了gradle 文件之后,就可以进行plugin 的开发了,在定义了uploadArchives 之后,会在testplugin 这个module 下产生一个名为uploadArchives 的Task,双击即可运行


image.png

这里指定的上传地址是本地地址,uploadArchives 运行成功之后就会在本地自定义的路径下看到一些文件,如图


image.png
1.0.0 是版本号,上级路径是包名,这里省略了,生成了这些文件,说明我们的插件生成成功了。

3. 编写代码

要实现plugin 的功能,需要创建一个类,实现Plugin<T> 接口,及apply 方法:

class TestPlugin implements Plugin<Project> {

    @Override
    void apply(Project project) {

        // 创建一个extension
        project.extensions.create("testPlugin", TestPluginExtension)

        // 创建一个task
        project.task('hello') {
            doLast {
                println("Hello ${project.testPlugin.filePath}")
            }
        }
    }
}

上面提到了创建一个extension,这个类的作用就是为插件提供一些可配置的属性,也就是我们可以从使用插件的模块的gradle 文件配置属性值来供插件使用。

class TestPluginExtension {
    String filePath
}

\color{#ff5533}{坑2}: 在新建groovy 文件时,如果采用 new → File → 文件名 → Register New File Type Association(选groovy)的方式创建groovy 文件有时候是不会为文件加 ".groovy" 后缀名的,如果没有后缀名,那么编译时就不会将这个文件编译,编译器不会报错,但是生成plugin 之后,在使用plugin 时就会报找不到某个类的错误。所以在新建一个文件之后要注意检查是不是有正确的后缀名,不要过于相信IDE。

上面的plugin 类中,除了创建一个extension 来定义可配置属性外,还创建了一个Task,如注释所写。上面这种方式是在plugin 类里直接定义了一个Task 的简单方式,当然也可以把Task 抽出来写成一个独立的类

class MagicTask extends DefaultTask{

    String filePath

    @TaskAction
    def taskMethod() { // task 要执行的任务代码

        filePath = project.testPlugin.filePath  // 1

        new SolveFile().solve(filePath)         // 2
    }
}

上面的filePath 的值可以直接从project 对象获取,如1处所示,由于groovy 也是基于JVM 的,也像Kotlin 一样能够无缝调用Java 代码,2处代码实际就是调用的Java 类的方法。

4. 使用自定义plugin

使用plugin 也比较简单,首先在Project 级的build.gradle 配置一下依赖

build.gradle(Project 级)

buildscript {
    ...
    repositories {
        ...
        maven {
            url uri('./repo')
        }
    }
    dependencies {
        ...
        classpath 'com.whx.testPlugin:testplugin:1.0.0'
    }
}

由于我们自定义plugin 时是上传的maven 仓库,所以在使用时的依赖库也要用maven,并用url 来指定地址。

\color{#ff5533}{坑3}:由于是本地的相对路径,注意路径的正确性,另外dependencies 中要使用classpath 声明,后面的形式是 “包名:module 名:版本号”。注意这些配置如果放在模块级 build.gradle 文件的话,maven 的url 地址可能会覆盖project 中的配置,从而导致依赖找不到等奇怪错误。

接下来,在我们要使用的模块的 build.gradle 文件中应用plugin 并配置属性:

build.gradle(module 级)

apply plugin: 'testPlugin'          // 1

testPlugin {                        // 2
    filePath = projectDir.absolutePath + '/src'
}
...

第一行就是应用我们的插件,第二行就是配置一些属性值来供插件使用,这些属性就是我们在TestPluginExtension 中定义的。

\color{#ff5533}{坑4}:第一行,应用的plugin ,值是我们自定义plugin 的id,这个值就是上面说的xxx.properties 的xxx,如果没有创建这个properties 文件,那么这个id 默认是实现了Plugin<T> 接口的类的全限定名。

至此,一个简单的自定义插件就完成了,只要避过了上面的几个坑就基本能跑通了。build 一下项目之后,会生成我们在plugin 类中声明的task,在Project 下,进入命令行输入

./gradlew taskName

就会执行Task。

另外关于自定义plugin,还有一些其他内容,包括groovy 的语法特性,gradle 的运行过程,plugin 的调试等,由于篇幅限制就不一一介绍了,这里就简单介绍一下gradle 的构建过程:

gradle构建的过程总共分为三个阶段:初始化阶段、配置阶段、运行阶段。

  • 初始化阶段是执行settings.gradle文件中的内容,看看这个Project需要构建哪几个module。

  • 配置阶段是从根Project依次遍历module,并为每个module生成一个Project对象,配置阶段完成时就形成了一个完整的task依赖图,同时配置阶段还会执行Task/Plugin 的初始化方法,定义期语句,configure 语句等,但不会执行真正要执行的内容。

  • 执行阶段就是执行Task,执行阶段不依赖脚本的定义顺序。

那么apply方法是什么时候执行的呢?
是在配置阶段遇到apply plugin:'testPlugin' 就开始执行, apply方法中传入的Project对象就是某个使用该插件的Project的对象。

二. 自定义gradle 插件的建议

可以看到plugin 就是一个 Plugin + Extension + Task 的一个模式,接收用户配置执行特定Task,所以我们可以把Plugin 类作为一个载体,只负责创建Extension 和Task,而不要实现业务逻辑;同时如果Task 比较多的话,可以创建一个辅助类TaskManager 来管理Task,另外Task 也是groovy 文件,如果我们对groovy 不熟悉,可以在Task 中调用Java 代码来实现功能。

相关文章

  • 自定义Gradle 插件及遇到的问题

    以自定义一个TestPlugin 的插件为例,记录一下遇到的坑。 一. 自定义Gradle 插件的步骤 1. 创建...

  • Gradle自定义插件

    Gradle自定义插件 在Gradle中创建自定义插件,Gradle提供了三种方式: 在build.gradle脚...

  • 自定义Gradle插件

    个人博客http://www.milovetingting.cn 自定义Gradle插件 自定义Gradle插件可...

  • Replugin源码解析之replugin-plugin-gra

    概述 该部分基础知识在Gradle学习-----Gradle自定义插件及Replugin源码解析之replugin...

  • Gradle系列7--调试Gradle插件

    前面几篇关于Gradle插件的开发。在开发过程中,遇到问题就需要找出问题出在哪里。这个问题是自定义插件中还是其他地...

  • 启用Gradle远程调试

    在Gradle学习10——自定义Gradle插件 这篇文章中介绍了编写插件的几种方式。编写gradle对象插件的实...

  • gradle插件调试

    在Gradle学习10——自定义Gradle插件 这篇文章中介绍了编写插件的几种方式。编写gradle对象插件的实...

  • Gradle 插件

    比如一个自动输出Lint报告的Gradle插件1.自定义Gradle插件的方式Gradle是采用Groovy语言,...

  • Android Gradle 插件(二)

    Android Gradle 插件(一)Android Plugin DSL Reference 自定义插件 新建...

  • Gradle自定义插件和发布

    Gradle自定义插件和发布 这篇文章讲解的是如何自定义gradle插件,并以本地依赖和远程依赖的方式来集成。 本...

网友评论

      本文标题:自定义Gradle 插件及遇到的问题

      本文链接:https://www.haomeiwen.com/subject/fozodctx.html