专栏名称: 郭霖
Android技术分享平台,每天都有优质技术文章推送。你还可以向公众号投稿,将自己总结的技术心得分享给大家。
目录
相关文章推荐
郭霖  ·  一文了解 Gradle 插件 ·  23 小时前  
鸿洋  ·  ANR?谁控制了触发时间? ·  22 小时前  
stormzhang  ·  钟睒睒的喊话,能改变什么? ·  3 天前  
51好读  ›  专栏  ›  郭霖

一文了解 Gradle 插件

郭霖  · 公众号  · android  · 2024-11-29 08:00

正文



/   今日科技快讯   /

据相关渠道透露,字节跳动起诉前实习生田柯宇篡改代码攻击公司内部模型训练一案,已获北京市海淀区人民法院正式受理。字节跳动请求法院,判令田柯宇赔偿公司侵权损失800万元及合理支出2万元,并公开赔礼道歉。

/   作者简介   /

明天周六啦,提前祝大家周末愉快!

本篇文章转自小墙程序员的博客,文章主要介绍Gradle了插件的开发与发布,相信会对大家有所帮助!

原文地址:
https://juejin.cn/post/7440718747491713061

/   前言   /

Gradle 插件是一种扩展 Gradle 构建工具功能的组件,我们可以使用它来协助我们打包、测试等。在开发过程中,我们离不开插件,比如创建一个Android项目,就需要如下的插件。

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 接口就可以了。

// 创建插件
class MyPluginPlugin<Project{

    override fun apply(target: Project) {
        println("MyPlugin apply")
    }
}

然后在当前模块的 build.gradle 中使用 apply() 来应用插件,注意需要把这部分代码放在 build.gradle 文件的最前面。点击构建后,就可以看到插件的执行了。效果如下图所示:


从上图可以看到,gradle 的插件在被 apply 时就被运行。为了能参与后面的构建过程,我们一般在插件中注册任务,而不是在插件中直接执行逻辑操作。代码示例如下:

class MyPlugin : Plugin<Project{

    override fun apply(target: Project) {
        println("MyPlugin apply")
        // 注册任务,执行操作
        target.tasks.register("myTask") {
            it.doLast {
                println("do something")
            }
        }
    }
}

自定义插件配置扩展

在Android中,我们常常看到如下的配置参数,这些都是Android插件构建需要的配置。

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 的

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
}

然后在插件中注册并获取对应的配置,代码示例如下:

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 中的配置如下:

my_extension {
    tag = "test_tag"
    user {
        name = "test_name"
        age = "test_age"
    }
}

注意:apply() 在 kotlin 脚本中有点问题,一直报获取不了自定义插件配置扩展的错误,需要本地发布依赖才能正常拉取配置。而同样的代码逻辑在 groovy 脚本中,使用 apply plugin 是没有问题的

/   打包   /

要想我们编写的二进制插件打包,需要先设置如下配置:

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 中设置如下依赖,并设置配置项。

id("maven-publish")

publishing {
    publications {
        create("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 中设置本地仓库的位置,代码如下所示:

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"
    }
}

同时在项目根目录中,依赖这个插件

buildscript {
    dependencies {
        classpath("com.example.plugin:MyPlugin:1.0.0")
    }
}

最后就可以在 build.gradle 中 apply 并配置 my_extension 的属性了。

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插件发布指南https://juejin.cn/post/7280062870669246525)。这篇文章已经讲得很详细了,我就不重复介绍了。

/   参考   /

插件教程:
https://juejin.cn/post/7267091810380136508
https://juejin.cn/post/6844903838290296846

Android 构建流程图
https://juejin.cn/post/6889090530593112077

官方源码: 
https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:build-system/gradle-core/

代码示例:
https://github.com/yechaoa/GradleX/blob/master/plugin/src/main/java/com/yechaoa/plugin/base/GradleXPlugin.java

推荐阅读:
我的新书,《第一行代码 第3版》已出版!
原创:写给初学者的Jetpack Compose教程,edge-to-edge全面屏体验
Android 15新特性,强制edge-to-edge全面屏体验

欢迎关注我的公众号
学习技术或投稿

长按上图,识别图中二维码即可关注