一文了解 Gradle 插件

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插件发布指南。这篇文章已经讲得很详细了,我就不重复介绍了。

参考

相关推荐
潘潘潘17 分钟前
Android多线程机制简介
android
CYRUS_STUDIO2 小时前
利用 Linux 信号机制(SIGTRAP)实现 Android 下的反调试
android·安全·逆向
CYRUS_STUDIO2 小时前
Android 反调试攻防实战:多重检测手段解析与内核级绕过方案
android·操作系统·逆向
黄林晴6 小时前
如何判断手机是否是纯血鸿蒙系统
android
火柴就是我6 小时前
flutter 之真手势冲突处理
android·flutter
法的空间6 小时前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
循环不息优化不止7 小时前
深入解析安卓 Handle 机制
android
恋猫de小郭7 小时前
Android 将强制应用使用主题图标,你怎么看?
android·前端·flutter
jctech7 小时前
这才是2025年的插件化!ComboLite 2.0:为Compose开发者带来极致“爽”感
android·开源
用户2018792831677 小时前
为何Handler的postDelayed不适合精准定时任务?
android