Gradle 插件是一种扩展 Gradle 构建工具功能的组件,我们可以使用它来协助我们打包、测试等。在开发过程中,我们离不开插件,比如创建一个Android项目,就需要如下的插件。
kotlin
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}
Gradle 插件和任务(Task)的区别
Gradle 任务是构建过程中的一个具体动作或操作单元,类似于一个个具体的功能代码。而 Gradle 插件则是组装这些 Task 的集合,类似于 SDK。
简单来说,Gradle 插件包含多个 Gradle 任务;Gradle 插件的功能是由一个个任务完成的。
插件
插件的种类
插件分成三种:脚本插件(Script Plugins)、预编译脚本插件(Precompiled Script Plugins)、二进制插件(Binary Plugins)
- 脚本插件,是指把代码写在构建脚本中,比如我们最熟悉的 build.gradle 文件
- 预编译脚本插件,则是把代码放在一个 buildSrc 文件中,方便该项目的其他模块使用
- 二进制插件,则是把代码打包成 jar 文件,供当前或者其他项目使用
自定义插件
上面提到过插件分为三种,它们之间的区别只是代码位置不同。为了体验插件编写和发布的全部流程,这里以二进制插件为例。首先我们先创建一个 module,如下图所示:
然后创建自己的插件类,我这里取名叫 MyPlugin
,代码示例如下。可以看到,实现插件的功能很简单,我们只需要实现 Plugin
接口就可以了。
kotlin
// 创建插件
class MyPlugin: Plugin<Project> {
override fun apply(target: Project) {
println("MyPlugin apply")
}
}
然后在当前模块的 build.gradle
中使用 apply<MyPlugin>()
来应用插件,注意需要把这部分代码放在 build.gradle 文件的最前面。点击构建后,就可以看到插件的执行了。效果如下图所示:
从上图可以看到,gradle 的插件在被 apply 时就被运行。为了能参与后面的构建过程,我们一般在插件中注册任务,而不是在插件中直接执行逻辑操作。代码示例如下:
kotlin
class MyPlugin : Plugin<Project> {
override fun apply(target: Project) {
println("MyPlugin apply")
// 注册任务,执行操作
target.tasks.register("myTask") {
it.doLast {
println("do something")
}
}
}
}
自定义插件配置扩展
在Android中,我们常常看到如下的配置参数,这些都是Android插件构建需要的配置。
kotlin
android {
namespace = "com.example.demo"
compileSdk = 34
defaultConfig {
applicationId = "com.example.demo"
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
...
}
如果你想要仿照Android的插件,也为自己的插件加上配置参数,可以定义如下的配置类。注意,class 必须是 open 的
kotlin
open class MyExtension {
var tag: String? = null
var user: MyUser? = null
constructor(project: Project) {
user = project.extensions.create("user", MyUser::class.java)
}
}
// 嵌套的配置
open class MyUser {
var name: String? = null
var age: String? = null
}
然后在插件中注册并获取对应的配置,代码示例如下:
kotlin
class MyPlugin : Plugin<Project> {
override fun apply(target: Project) {
println("MyPlugin apply")
val extension = target.extensions.create("my_extension", MyExtension::class.java)
target.tasks.register("fetchextension") {
it.doLast {
println("extension tag = ${extension.tag}")
println("name: ${extension.user?.name} age: ${extension.user?.age}")
}
}
}
}
完成这些步骤后,我们就可以在 build.gradle 中的配置如下:
ini
my_extension {
tag = "test_tag"
user {
name = "test_name"
age = "test_age"
}
}
注意;
apply<MyPlugin>()
在 kotlin 脚本中有点问题,一直报获取不了自定义插件配置扩展的错误,需要本地发布依赖才能正常拉取配置。而同样的代码逻辑在 groovy 脚本中,使用apply plugin
是没有问题的
打包
要想我们编写的二进制插件打包,需要先设置如下配置:
bash
plugins {
id("java-gradle-plugin")
id("org.jetbrains.kotlin.jvm")
}
gradlePlugin {
plugins{
create("myPlugin") {
id = "com.example.plugin.MyPlugin"
implementationClass = "com.demo.plugin.MyPlugin"
}
}
}
其中,id 是插件的唯一标识,就是我们应用插件时设置的,比如应用android插件 id("org.jetbrains.kotlin.android")
;implementationClass
则是我们插件的实现类的路径。完成这边步骤后,我们就可以对编写完成的插件进行发布了。
插件发布
插件发布分为本地发布和远端发布两种,下面将分别介绍。
本地发布
本地发布,顾名思义就是把打包的jar发布到本地仓库。要想实现这个功能,我们需要先在当前模块的 build.gradle 中设置如下依赖,并设置配置项。
kotlin
id("maven-publish")
publishing {
publications {
create<MavenPublication>("mavenJava") {
groupId = "com.example.plugin"
artifactId = "MyPlugin"
version = "1.0.0"
from(components["java"])
}
}
// 配置仓库
repositories {
maven {
name = "localPluginRepository"
url = uri("../local-plugin-repository")
}
}
}
dependencies {
implementation("com.android.tools.build:gradle:7.3.1")
}
执行 ./gradlew publish
命令后,就可以在本地仓库看到发布成的包了。
如果我们想要在项目中使用这个包,需要在 setting.gradle 中设置本地仓库的位置,代码如下所示:
scss
pluginManagement {
repositories {
maven {
// 设置本地仓库的路径
setUrl("./local-plugin-repository")
}
google {
content {
includeGroupByRegex("com\.android.*")
includeGroupByRegex("com\.google.*")
includeGroupByRegex("androidx.*")
}
}
mavenCentral()
gradlePluginPortal()
}
plugins {
kotlin("jvm") version "2.0.0"
}
}
同时在项目根目录中,依赖这个插件
scss
buildscript {
dependencies {
classpath("com.example.plugin:MyPlugin:1.0.0")
}
}
最后就可以在 build.gradle 中 apply 并配置 my_extension 的属性了。
kotlin
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
id("com.example.plugin.MyPlugin")
}
android {
...
}
my_extension {
tag = "test_tag"
user {
name = "test_name"
age = "test_age"
}
}
远端发布
远端发布流程可以看 Yechaoa 大佬的 【Gradle-9】Gradle插件发布指南。这篇文章已经讲得很详细了,我就不重复介绍了。