自定义 Gradle 插件

Android 中许多优秀的开源框架都会自定义 Gradle 插件,比如,热修复的 Tinker

所以,这篇文章记录 Android Studio 中如何自定义 Gradle 插件。


Gradle

Gradle 是个的构建工具,也是Android Studio 默认的构建工具,与传统的 Ant 、maven 相比,Gradle 更加强大。利用 Gradle 这个工具,我们能做很多事情,例如热修复、插件化等等。

当然,这篇文章不会将具体的 Gradle 语法,这篇文章只会记录如何创建一个Gradle 插件。

如果你想彻底理解并应用 Gradle ,推荐看这系列文章 Gradle for Android

Gradle 插件是使用 Groovy 语言进行开发的,而 Groovy 是可以兼容 Java 的。Android Studio 除了开发 APP 外,完全可以开发 Gradle 插件。


插件开发

现在来说下,详细的 Gradle 插件开发步骤:

  1. 新建一个项目

  2. 再新建一个 Module,此 Module 用于开发插件,类型选什么都无所谓,后面会大改。

  3. 在 Project 目录视图模式下,清空 build.gradle 文件的内容,删除其余的所有文件。

  4. 然后在 module 中新建多个文件夹 src/main/groovy ,再新建包名文件夹。 在 main 目录下再新建resources 目录,在resources 目录下再新建 META-INF 文件夹,再新建文件夹gradle-plugins,这样就完成了 gradle 插件的目录结构搭建,整个目录结构如下。

  5. 打开 build.gralde 文件,替换全部内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    apply plugin: 'groovy'
    apply plugin: 'maven'

    dependencies {
    compile gradleApi() //gradle sdk
    compile localGroovy() //groovy sdk
    }

    repositories {
    jcenter()
    }
  6. 现在,就可以来正式写插件内容了。在刚刚新建的包名下 再次新建一个文件 MyPlugin.groovy ,注意文件类型,一定是 groovy 类型文件,刚开始没注意,直到出了问题,排查时,打开本地文件才发现文件没有后缀名称。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package com.app.plugin

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

    public class MyPlugin implements Plugin<Project> {

    void apply(Project project) {
    def log = project.logger
    log.error "========================";
    log.error "完整的MyPlugin,开始修改Class!";
    log.error "========================";
    }
    }
  7. resources/META-INF/gradle-plugins 目录下新建一个 .properties 文件,注意该文件的命名就是你使用此插件时的名称,这里命名为 com.app.myplugin.properties ,一定要注意后缀名称,那么使用时的名称就是com.app.myplugin,文件里面的内容填写如下:

    1
    implementation-class=com.app.plugin.MyPlugin

    这里是 key = value 的形式,值就是刚刚自定义的 插件( groovy 文件 )的全名,也就是路径加上类名称。



至此,插件也就开发完成了。

这是可以发布出去的完整的插件结构,如果你想开发只针对当前项目的 Gradle 插件,那么可以简化很多步骤,也可以忽略后面的打包发布的繁琐步骤。



简化版 gradle 插件

开发仅用于当前项目的简化版 Gradle 插件的话,绝大部分与前面完整的步骤相同,只是有两点需要注意:

  1. 用于开发插件的 Module 名称必须是 BuildSrc
  2. 无须 resources 目录

整个目录结构简化了许多。

而且 build.gradle 中也去除了 maven 插件 apply plugin: 'maven' ,文件如下:

1
2
3
4
5
6
7
8
9
10
apply plugin: 'groovy'

dependencies {
compile gradleApi() //gradle sdk
compile localGroovy() //groovy sdk
}

repositories {
jcenter()
}

然后就是编写的插件,MyPlugin.groovy 文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.example

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

public class MyPlugin implements Plugin<Project> {

void apply(Project project) {
def log = project.logger
log.error "========================";
log.error "精简的MyPlugin,开始修改Class!";
log.error "========================";
}
}

如果是使用的话,就直接在需要使用的 module 中 build.gradle 添加

1
apply plugin: com.example.MyPlugin //注意,这里没有单引号,直接填写插件的全名

然后,先 clean 下项目,然后 make project ,就可以在控制台看到效果:



插件的发布

当然,如果你想复用 你的gradle 插件,那就必须把它发布出去。

按发布的地点分类,有两种:

  1. 发布到本地仓库
  2. 发布到远程仓库


本地仓库

如果是发布到本地,则在插件的build.gradle 中添加如下代码 :

1
2
3
4
5
6
7
8
uploadArchives {
repositories.mavenDeployer {
repository(url: uri('../repo')) //仓库的路径,此处是项目根目录下的 repo 的文件夹
pom.groupId = 'com.app.plugin' //groupId ,自行定义,一般是包名
pom.artifactId = 'gradleplugin' //artifactId ,自行定义
pom.version = '1.0.0' //version 版本号
}
}

此处的 groupIdartifactIdversion 这三个参数都是自定义的,后面再引用这个插件时会用到。

maven 本地仓库的目录就是当前项目目录下的 repo 目录,这个时候右侧的 gradle Toolbar 就会在module下多出一个task ,upload-uploadArchives ,在运行这个Task 之前,需要先 clean 项目。运行过后,就会在项目中生成一个 repo 的文件夹,里面就存放着发布的 gradle 插件。


使用时,需要在根目录的 build.gradle 中添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
buildscript {
repositories {
//首先需要配置本地的 maven 仓库地址,这里填写的是相对路径,也可以是全路径
maven {
url uri('repo')
}
}
dependencies {
//然后,添加依赖的插件,形式是 groupId:artifactId:version
//这些都是插件发布时,定义的名称
classpath 'com.app.plugin:gradleplugin:1.0.0'
}
}

最后,在使用的 module 的 build.gradle 里,添加

1
apply plugin: 'com.app.plugin.myplugin' //这里就填写 .properties 文件的名称

这就完成了本地仓库的插件使用。重新构建工程后,效果如下:


远程仓库

发布插件到远程仓库的方法,我在网上搜索到几个方案,都不成功。

幸好 有 Gradle Plugins 这样一个门户网站,让我们可以快速发布 Gradle 的插件,它有一个使用的教程文档,在这里放上 地址 ,你也可以直接看文档。


现在来简单介绍如果使用:

  1. 首先需要在这个门户网站 https://plugins.gradle.org/ 中注册账户,它也可以支持 Github 账户登录。

  2. 然后在自己的账户界面,点击 API Keys ,获取 key 和 secret ,将他们 copy 到项目的 gradle.properties 文件中。

  3. 然后在将要发布的插件 module 的 build.gradle 文件中做如下配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    apply plugin: 'groovy'
    apply plugin: "com.gradle.plugin-publish"

    dependencies {
    compile gradleApi() //gradle sdk
    compile localGroovy() //groovy sdk

    //这里根据插件需要,添加对应的依赖
    compile 'com.android.tools.build:gradle:3.0.0'
    compile 'org.javassist:javassist:3.20.0-GA'
    }
    repositories {
    jcenter()
    }


    buildscript {
    repositories {
    maven {
    url "https://plugins.gradle.org/m2/"
    }
    }
    dependencies {
    classpath "com.gradle.publish:plugin-publish-plugin:0.9.7"
    }
    }

    repositories {
    mavenCentral()
    jcenter()
    }

    version = "1.0.0" //配置插件的版本号
    group = "com.deemons.gradlePlugin" //插件的群组,插件的classpath会用到

    pluginBundle {

    website = 'http://www.gradle.org/'
    vcsUrl = 'https://github.com/gradle/gradle'
    description = 'javassist for okbus' //插件描述
    tags = ['okbus', 'javassist'] //插件的tag。可以通过这个在插件门户上搜索

    plugins {
    greetingsPlugin {
    id = 'com.deemons.bus' //插件的id,到时候apply的插件id
    displayName = 'OkBus plugin'
    }
    }
    }
  4. 添加完成后并且同步后,右侧对应模块的 Tasks 目录下,会多出 plugin portal ,然后点击 publishPlugins 就完成发布了。


如果不出意外,插件就已经上传好了,这时候在 Plugins 上就可以搜索到自己的插件了。

点击进入,查看插件详情,里面会告诉你这个插件是如何使用的,是不是非常方便~


这篇文章只是简单的介绍了 gradle 插件的开发,但真正有难度的是插件的内容。比如,结合 AspectJ 或者javassist 完成功能强大的插件,例如 TinkerRePluginVirtualAPK 等。



参考