上一篇我们介绍了 gradle 插件相关的概念,没看的同学可以点击这里查看,这一篇让我们结合例子来看看如何一步步创建一个 gradle 插件,并在 Android 项目中使用。
工欲善其事必先利其器,要开发 gradle 插件得先决定用什么开发环境。我自己使用过 Intellij IDEA 和 AndroidStudio 来开发,因为 AndroidStudio 是基于 Intellij 改的,所以区别不是很大。
但就我个人的偏好来说更偏向于 Intellij,因为 AndroidStudio 是专门用来开发 Android 的,有很多配套的调试按钮,如果用来开发一个纯的 gradle 插件项目就会很别扭,所以我的判断原则是:
- 如果是一个纯的 gradle 插件项目,用 Intellij IDEA。
- 如果是 Android 项目中内嵌的 gradle 插件项目,比如一个 module 用来放插件的代码,用 AndroidStudio。
gradle 插件比较主流的开发语言是 groovy,因为 gradle 就是用 groovy 写的。通过查看第三方写的 gradle 插件代码发现大部分也是用 groovy 写的。
除了 groovy 还可以用来开发 gradle 插件的语言有:
- java
- kotlin
- 其它基于 jvm 语言
因为 groovy 是基于 jvm 的,所以同样基于 jvm 的也可以用来写 gradle 插件。但 java 和 kotlin 是静态语言,意味着需要不停地判断类型和强转,相比之下,groovy 作为动态语言就没有这个问题。所以本文后续的插件代码都是 groovy 写的。
具体开发之前让我们先来看看要开发的 gradle 插件要满足什么需求。
实现一个插件,名字叫 io.helloworld.myplugin
,需要实现下面的功能:
- 进行 Android 自动配置
- minSdkVersion 设置为 21
- targetSdkVersion 设置为 26
- compileSdkVersion 设置为 29
- buildToolsVersion 设置为 ‘29.0.2’
- 注册一个 Task,名字叫
myTask
。
-
打开 Intellij IDEA,按 file -> new -> project 创建一个新项目。在 「new project」对话框左边选择 gradle,右边的 「Additional Libraries and Frameworks」只选择 Groovy:
-
下一个界面选择代表你这个插件包的 groupId 和 ArtifactId,例如
io.helloworld.robot
和gradletools
,版本号可以保持默认不变1.0-SNAPSHOT
groupId、artifactId 和 version 构成了我们这个插件包的标识 Id,另一个项目如果想使用我们这个插件时,就需要通过这个 Id 来声明依赖。
-
然后点 「next」-> 「finish」,项目结构大概像下面这样:
-
因为要用到 gradle 的依赖,所以需要在项目 build.gradle 脚本文件中加一条 gradle 的依赖:
dependencies { implementation gradleApi() ... }
创建项目时,IDE 会默认添加上 groovy 的依赖:
implementation 'org.codehaus.groovy:groovy-all:2.3.11'
为了防止出现 groovy 版本不一致的问题,这里的依赖最好换成下面这样,让 gradle 自动去获取本地的 groovy 版本。
implementation localGroovy()
然后点一下 gradle 的同步按钮,保证 IDE 能引用到对应的类。
-
在 groovy 文件夹下创建包
io.helloworld.robot
,和前面设置的 groupId 保持一致。在这个包下创建一个 groovy 类MyPlugin
,代码如下:package io.helloworld.robot import org.gradle.api.Plugin import org.gradle.api.Project class MyPlugin implements Plugin<Project> { @Override void apply(Project project) { println("beginning of plugin 'MyPlugin'") } }
可以看到
MyPlugin
实现了Plugin<Project>
的接口,而这个接口有一个方法apply(Project project)
,猜测当我们这个插件在build.gradle
中应用时,这个方法会被调用,我们在这个方法中加上一行打印调试信息的代码。这里创建的插件是给
build.gradle
用的,所以Plugin
的泛型类型是Project
,如果给settings.gradle
用的话,泛型类型应该是Settings
。现在我们的插件已经创建好了(虽然很简陋),那怎样才能让 Android 项目使用到它呢?还需要再做两件事:创建插件的声明文件和将包含插件的软件包发布到 maven 仓库。
-
创建插件的声明文件
需要在 resources 文件夹下创建文件夹 META-INF/gradle-plugins,所有插件的声明文件都要放在这个目录下:
插件的声明文件都是后缀为
properties
的配置文件,文件名就是插件的名字,例如这里的插件名字就是io.helloworld.myplugin
。在文件中通过implementation-class
的值关联到上面创建的插件类MyPlugin
:implementation-class=io.helloworld.robot.MyPlugin
-
发布到 maven 仓库
因为 maven 仓库不是这篇文章的重点,所以简单起见,这里将包含插件的软件包发布到本地仓库。
要发布到本地仓库,
build.gradle
需要加上下面这些代码:apply plugin: 'maven-publish' publishing { publications { mavenPub(MavenPublication) { // 这一行表示将 jar 包包含在要发布的组件中 from components.java // 描述性信息 pom { name = 'Robot MyPlugin' description = 'This is a test project for gradle plugin.' url = 'http://www.helloworld.com' } } } repositories { maven { // 本地 repo 地址,这里写上你们电脑上自己的地址 url = '/Users/zhanglei/projects/repo' } } }
这里使用
maven-publish
插件来发布到 maven 仓库,其实发布到网络上也是类似的,将上面代码的url
改成网络地址,再加上用户名/密码就可以了。改好
build.gradle
后点一下 gradle 的同步按钮,在 gradle 窗口的 Tasks 条目下就会看到 publishing 的 Task 分组,其中可以找到「publish」Task:双击执行这个 Task 来发布组件,执行结束后在上述本地仓库的地址下可以看到组件已经发布成功:
OK,所有的准备工作都做完了,现在可以使用插件了。
-
在 Android 项目中使用插件
因为我们的插件是配置 Android 相关信息,所以要在 application 类型的 module 下使用。在 AndroidStudio 中打开 module 下的
build.gradle
文件,加上下面的代码:// 使用插件 apply plugin: 'io.helloworld.myplugin' buildscript { repositories { // 声明本地 repo 的地址 maven { url '/Users/zhanglei/projects/repo' } } dependencies { // 声明依赖我们上面发布到本地 maven 仓库的软件包 classpath 'io.helloworld.robot:gradletools:1.0-SNAPSHOT' } }
因为插件发布在本地仓库中,所以要在 buildscript.repositories 中声明一下仓库地址。然后在 AndroidStudio 中同步下 gradle 就可以看到我们刚才写在
apply()
中的调试代码输出的 log:AndroidStudio 中同步 gradle 和 Intellij 中稍微有点不一样:点下面这个按钮:
好的,我们现在把开发插件到使用插件这条路调通了,接下来我们在插件中完成上面说的「插件需求」,先来看看第一个:
-
实现插件功能一:进行 Android 自动配置
- minSdkVersion 设置为 21
- targetSdkVersion 设置为 26
- compileSdkVersion 设置为 29
- buildToolsVersion 设置为 29.0.2
在 Intellij 中打开 MyPlugin 类,在
apply()
方法中加上下面这段代码:project.extensions.findByName('android').with { getProperty('defaultConfig').with { setProperty('minSdkVersion', 21) setProperty('targetSdkVersion', 26) } setProperty('compileSdkVersion', 29) setProperty('buildToolsVersion', '29.0.2') }
然后发布到本地仓库,然后在 AndroidStudio 中同步下 gradle,这就相当于在
build.gradle
中写了:android { defaultConfig { minSdkVersion 21 targetSdkVersion 26 } compileSdkVersion 29 buildToolsVersion '29.0.2' }
第一个需求完成了,接下来看一下第二个需求。
-
实现插件功能二:注册一个 Task
myTask
打开
MyPlugin
,在apply()
方法中加上下面这段代码:project.task('myTask') { group 'helloworld' description 'This is a task named myTask, created in myPlugin' doFirst { println("run in myTask it $it") } }
这里创建了一个名叫
myTask
的 Task,并设置了 group、description 和它的运行代码。和上面一样,将插件发布到本地仓库,并同步 Android 项目的 gradle。可以看到 Android 项目中已经存在myTask
Task:
到这里一个拥有基本功能的 gradle 插件就开发好了,如果想继续扩展这个插件的功能,就继续在 apply()
方法里添加代码。因为 apply()
方法的参数是 project,所以这里可以实现 build.gradle
中的所有能力。你也可以在这个项目中开发一个新的插件,放一些特殊的 gradle 处理逻辑。
关于 gradle 插件开发就简单介绍到这里,由于我也是边开发边学习,难免有一些不对的地方,欢迎大家评论指正。