一、插件到底是个啥?

说实话,我刚接触 Gradle 那会儿,对「插件」这个概念挺模糊的。总觉得它是个很玄乎的东西,好像离我很远。

后来做项目做多了,慢慢就明白了——插件其实就是一段可复用的构建逻辑。你想想看,我们每天都在用插件:

  • apply plugin: 'com.android.application' —— 这是 Android 官方插件
  • apply plugin: 'kotlin-android' —— 这是 Kotlin 插件
  • apply plugin: 'com.google.gms.google-services' —— 这是 Google 服务插件

说白了,插件就是把一堆 Task、配置、扩展属性打包起来,让你能一键复用。没有插件的话,你每个项目都得手写那些编译、打包、签名、混淆的逻辑……想想就头大。

核心理解:插件 = 构建逻辑的封装单元。它让 Gradle 从「一个构建工具」变成了「一个可扩展的构建平台」。

二、插件的三种类型

Gradle 插件分三种,我按使用场景给你捋一捋。

1. 脚本插件

这是最原始、最直接的方式。说白了就是一个 .gradle 文件,里面写一堆逻辑,然后别的脚本用 apply from 把它引进来。

// version.gradle
ext {
    compileSdkVersion = 34
    minSdkVersion = 21
    targetSdkVersion = 34
}

// app/build.gradle
apply from: '../version.gradle'
android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    // ...
}

我在早期项目里经常这么干。好处是简单,坏处是……嗯,你没法控制别人怎么用你的脚本,也没法传参数。说白了就是「裸奔」。

2. 二进制插件

这就是我们平时用的那种插件。它被打包成 jar 或者 aar,通过 apply plugin: '插件ID' 来使用。Android 插件、Kotlin 插件都属于这一类。

二进制插件的好处是:

  • 可以传参数(通过 extension)
  • 可以控制执行顺序
  • 可以依赖其他插件
  • 可以发布到仓库供别人使用

3. 预编译脚本插件

这是 Gradle 7.0 之后推出的新玩法。它本质上还是脚本,但被编译成了 .class 文件,所以性能更好,而且可以像二进制插件一样用 apply plugin 来引用。

// buildSrc/src/main/kotlin/my-library.gradle.kts
plugins {
    id("com.android.library")
    id("org.jetbrains.kotlin.android")
}

android {
    compileSdk = 34
    defaultConfig {
        minSdk = 21
    }
}

// app/build.gradle.kts
plugins {
    id("my-library")
}

我个人比较推荐这种方式。它既有脚本的灵活性,又有二进制插件的性能。我在团队里推广过,大家反馈都不错。

我的建议:新项目优先考虑预编译脚本插件。如果逻辑特别复杂,再考虑写二进制插件。

三、三种插件的对比

类型 定义方式 使用方式 性能 适用场景
脚本插件 .gradle 文件 apply from 一般 简单配置共享
二进制插件 Java/Kotlin 类 apply plugin 复杂构建逻辑
预编译脚本插件 .gradle.kts 文件 apply plugin 较好 模块化配置

四、知识体系总览

在动手写插件之前,我们先看看整个知识结构长什么样:

Gradle 插件知识体系 Gradle 插件 脚本插件 二进制插件 预编译脚本插件 apply from 引用 简单直接 无法传参 apply plugin 引用 支持 extension 可发布到仓库 编译为 .class 性能较好 推荐使用 核心:插件 = 构建逻辑的封装单元

五、创建第一个自定义插件

好,理论说完了,咱们动手写一个。我带你写一个最简单的插件——它只做一件事:在构建开始前打印一条日志。

步骤 1:创建 buildSrc 模块

在项目根目录下创建 buildSrc 文件夹,里面放一个 build.gradle.kts:

// buildSrc/build.gradle.kts
plugins {
    `kotlin-dsl`
}

repositories {
    mavenCentral()
}

然后创建源码目录:buildSrc/src/main/kotlin/

步骤 2:写插件类

// buildSrc/src/main/kotlin/com/example/HelloPlugin.kt
package com.example

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

class HelloPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.tasks.register("hello") {
            doLast {
                println("👋 Hello from my first plugin!")
            }
        }
    }
}

这里要注意,Plugin 接口的泛型参数是 Project。这意味着你的插件作用于整个 Project 层面。如果你想作用于某个 Task,那又是另一种写法了。

步骤 3:注册插件 ID

在 buildSrc/src/main/resources/META-INF/gradle-plugins/ 目录下,创建一个 properties 文件:

# buildSrc/src/main/resources/META-INF/gradle-plugins/com.example.hello.properties
implementation-class=com.example.HelloPlugin

文件名就是你的插件 ID。我习惯用包名作为前缀,这样不容易冲突。

步骤 4:使用插件

// app/build.gradle.kts
plugins {
    id("com.example.hello")
}

然后执行 ./gradlew hello,你就会看到控制台打印出那句问候语。

我曾经踩过的坑:buildSrc 的改动需要重新同步 Gradle。有时候改了代码但没同步,结果插件还是旧版本。记得每次改完 buildSrc 都点一下「Sync Now」。

六、发布到本地仓库

插件写好了,总不能只在 buildSrc 里用吧?我想把它发布到本地仓库,让其他项目也能引用。

步骤 1:配置发布脚本

在插件的 build.gradle.kts 里加上 maven-publish 插件:

plugins {
    `kotlin-dsl`
    `maven-publish`
}

group = "com.example"
version = "1.0.0"

publishing {
    publications {
        create<MavenPublication>("plugin") {
            from(components["kotlin"])
        }
    }
    repositories {
        maven {
            name = "localRepo"
            url = uri("${rootProject.projectDir}/repo")
        }
    }
}

步骤 2:执行发布

运行 ./gradlew publishPluginPublicationToLocalRepoRepository,插件就会被发布到项目根目录下的 repo 文件夹里。

步骤 3:在其他项目中使用

// settings.gradle.kts
pluginManagement {
    repositories {
        maven {
            url = uri("${rootProject.projectDir}/repo")
        }
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}

// app/build.gradle.kts
plugins {
    id("com.example.hello") version "1.0.0"
}
小技巧:本地仓库的路径可以用相对路径,也可以用绝对路径。我一般用相对路径,这样项目拷贝到别的机器上也能用。

七、总结一下

这一章我们聊了:

  • 插件是什么——说白了就是构建逻辑的封装
  • 三种插件类型——脚本、二进制、预编译脚本
  • 怎么创建第一个插件——从 buildSrc 开始
  • 怎么发布到本地仓库——用 maven-publish

我个人觉得,插件开发是 Gradle 进阶路上必须跨过的一道坎。它不难,但需要你理解 Gradle 的运作方式。下一章我们会深入插件的内部结构,看看 extension 和 task 是怎么配合的。

嗯,今天就到这儿。动手试试吧,有问题随时交流。


公众号:蓝海资料掘金营,微信deep3321