MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Kotlin中的Gradle插件开发与自定义任务

2024-11-125.1k 阅读

Kotlin 中的 Gradle 插件开发基础

Gradle 插件概述

Gradle 是一个基于 Apache Ant 和 Apache Maven 概念的项目自动化构建工具。它使用一种基于 Groovy 的特定领域语言(DSL)来声明项目设置,抛弃了基于 XML 的传统方式。Gradle 插件则是扩展 Gradle 功能的重要方式,通过插件可以添加新的任务、配置选项等,以满足各种项目的构建需求。

在 Kotlin 项目开发中,Gradle 被广泛应用于构建、测试、依赖管理等各个方面。例如,kotlin - gradle - plugin 就是专门用于支持 Kotlin 语言开发的 Gradle 插件,它使得 Gradle 能够编译、测试 Kotlin 代码。

创建 Gradle 插件项目

  1. 项目结构初始化 首先,我们可以使用 Gradle 本身来初始化一个插件项目。在命令行中执行以下命令:
    gradle init --type kotlin - gradle - plugin
    
    这会创建一个基本的 Gradle 插件项目结构,如下所示:
    my - kotlin - plugin
    ├── build.gradle.kts
    ├── gradle
    │   └── wrapper
    │       ├── gradle - wrapper.jar
    │       └── gradle - wrapper.properties
    ├── gradlew
    ├── gradlew.bat
    ├── settings.gradle.kts
    └── src
        └── main
            ├── kotlin
            │   └── com
            │       └── example
            │           └── my - kotlin - plugin
            │               └── MyKotlinPlugin.kt
            └── resources
                └── META - INF
                    └── gradle - plugins
                        └── com.example.my - kotlin - plugin.properties
    
  2. 核心文件解析
    • MyKotlinPlugin.kt:这是插件的主实现类。在 Kotlin 中,插件类通常继承自 Plugin<Project> 接口。例如:
    package com.example.my - kotlin - plugin
    
    import org.gradle.api.Plugin
    import org.gradle.api.Project
    
    class MyKotlinPlugin : Plugin<Project> {
        override fun apply(target: Project) {
            // 插件逻辑在此处实现
        }
    }
    
    • com.example.my - kotlin - plugin.properties:这个文件用于配置插件的元数据。内容如下:
    implementation - class = com.example.my - kotlin - plugin.MyKotlinPlugin
    
    它指定了插件的实现类。

简单插件示例:打印项目信息

  1. 实现插件逻辑MyKotlinPlugin.kt 中,我们可以实现一个简单的逻辑,打印项目的名称和版本。修改 apply 方法如下:
    package com.example.my - kotlin - plugin
    
    import org.gradle.api.Plugin
    import org.gradle.api.Project
    
    class MyKotlinPlugin : Plugin<Project> {
        override fun apply(target: Project) {
            target.logger.lifecycle("Project name: ${target.name}")
            target.logger.lifecycle("Project version: ${target.version}")
        }
    }
    
  2. 使用插件 要使用这个插件,我们需要在另一个项目的 build.gradle.kts 文件中应用它。假设我们有一个简单的 Kotlin 项目,其 settings.gradle.kts 文件中包含:
    rootProject.name = "my - app"
    
    并且 build.gradle.kts 文件如下:
    plugins {
        kotlin("jvm") version "1.6.21"
    }
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        implementation(kotlin("stdlib - jdk8"))
    }
    
    apply(plugin = "com.example.my - kotlin - plugin")
    
    注意这里通过 apply(plugin = "com.example.my - kotlin - plugin") 应用了我们自定义的插件。当我们在这个项目目录下执行 ./gradlew build 时,在构建日志中会看到:
    > Task :lifecycleProject name: my - app
    > Task :lifecycleProject version: unspecified
    
    这里的 unspecified 是因为我们没有在项目中显式设置版本号。

自定义 Gradle 任务

Gradle 任务基础

  1. 任务概念 Gradle 任务是构建过程中执行的最小工作单元。例如,编译代码、测试代码、打包等都可以是一个任务。任务可以依赖其他任务,形成一个任务执行的有向无环图(DAG)。Gradle 会根据任务之间的依赖关系,以最优的顺序执行任务。
  2. 任务类型
    • 内置任务:Gradle 提供了许多内置任务,如 compileJava 用于编译 Java 代码,test 用于执行测试等。
    • 自定义任务:开发人员可以根据项目需求定义自己的任务。在 Kotlin 中,自定义任务通常通过继承 DefaultTask 类来实现。

创建自定义任务

  1. 定义任务类 在插件项目的 src/main/kotlin/com/example/my - kotlin - plugin 目录下,创建一个新的 Kotlin 文件,例如 MyCustomTask.kt
    package com.example.my - kotlin - plugin
    
    import org.gradle.api.DefaultTask
    import org.gradle.api.tasks.TaskAction
    
    open class MyCustomTask : DefaultTask() {
        @TaskAction
        fun executeTask() {
            logger.lifecycle("This is my custom task.")
        }
    }
    
    这里,MyCustomTask 继承自 DefaultTask@TaskAction 注解标记了任务执行时要调用的方法。
  2. 在插件中注册任务MyKotlinPlugin.ktapply 方法中注册这个任务:
    package com.example.my - kotlin - plugin
    
    import org.gradle.api.Plugin
    import org.gradle.api.Project
    import org.gradle.api.tasks.TaskProvider
    
    class MyKotlinPlugin : Plugin<Project> {
        override fun apply(target: Project) {
            val myCustomTask: TaskProvider<MyCustomTask> = target.tasks.register("myCustomTask", MyCustomTask::class.java)
            target.logger.lifecycle("Project name: ${target.name}")
            target.logger.lifecycle("Project version: ${target.version}")
        }
    }
    
    通过 target.tasks.register 方法注册了 myCustomTask 任务。现在,当我们在应用该插件的项目中执行 ./gradlew tasks 时,会看到 myCustomTask 任务出现在任务列表中。执行 ./gradlew myCustomTask 就会执行我们定义的任务逻辑,输出 This is my custom task.

自定义任务参数

  1. 添加参数属性 我们可以给自定义任务添加参数属性,使其更加灵活。修改 MyCustomTask.kt 如下:
    package com.example.my - kotlin - plugin
    
    import org.gradle.api.DefaultTask
    import org.gradle.api.tasks.Input
    import org.gradle.api.tasks.TaskAction
    
    open class MyCustomTask : DefaultTask() {
        @get:Input
        var message: String = "Default message"
    
        @TaskAction
        fun executeTask() {
            logger.lifecycle("Message from task: $message")
        }
    }
    
    这里,message 是一个自定义参数,@Input 注解表示该属性是任务的输入,Gradle 会根据其值的变化来判断任务是否需要重新执行。
  2. 在插件中配置参数MyKotlinPlugin.kt 中配置任务参数:
    package com.example.my - kotlin - plugin
    
    import org.gradle.api.Plugin
    import org.gradle.api.Project
    import org.gradle.api.tasks.TaskProvider
    
    class MyKotlinPlugin : Plugin<Project> {
        override fun apply(target: Project) {
            val myCustomTask: TaskProvider<MyCustomTask> = target.tasks.register("myCustomTask", MyCustomTask::class.java) {
                it.message = "Customized message"
            }
            target.logger.lifecycle("Project name: ${target.name}")
            target.logger.lifecycle("Project version: ${target.version}")
        }
    }
    
    现在,当执行 myCustomTask 任务时,会输出 Message from task: Customized message

Gradle 插件开发进阶

插件依赖管理

  1. 添加外部依赖 在插件项目的 build.gradle.kts 文件中,可以添加插件所需的外部依赖。例如,如果插件需要使用 Kotlin 的标准库扩展函数,我们可以添加如下依赖:
    dependencies {
        implementation(kotlin("stdlib - jdk8"))
    }
    
    这会将 Kotlin 标准库的相关依赖添加到插件项目中,使得插件代码可以使用其中的功能。
  2. 依赖传递 当插件被应用到其他项目时,插件的依赖默认不会传递给使用插件的项目。如果希望某些依赖能够传递,可以在 build.gradle.kts 中使用 api 配置。例如:
    dependencies {
        api(kotlin("stdlib - jdk8"))
    }
    
    使用 api 配置的依赖会传递给使用该插件的项目,这样在使用插件的项目中就可以直接使用这些依赖中的类和方法,而无需再次声明依赖。

插件配置扩展

  1. 创建配置扩展类 假设我们希望在应用插件的项目中可以配置一些特定的参数,例如一个字符串配置和一个整数配置。在插件项目的 src/main/kotlin/com/example/my - kotlin - plugin 目录下创建 MyPluginExtension.kt
    package com.example.my - kotlin - plugin
    
    open class MyPluginExtension {
        var customString: String = "default string"
        var customInt: Int = 10
    }
    
  2. 在插件中注册配置扩展MyKotlinPlugin.kt 中注册这个配置扩展:
    package com.example.my - kotlin - plugin
    
    import org.gradle.api.Plugin
    import org.gradle.api.Project
    
    class MyKotlinPlugin : Plugin<Project> {
        override fun apply(target: Project) {
            val extension = target.extensions.create("myPluginExtension", MyPluginExtension::class.java)
            target.tasks.register("printExtension") {
                it.doLast {
                    target.logger.lifecycle("Custom string: ${extension.customString}")
                    target.logger.lifecycle("Custom int: ${extension.customInt}")
                }
            }
            target.logger.lifecycle("Project name: ${target.name}")
            target.logger.lifecycle("Project version: ${target.version}")
        }
    }
    
    这里通过 target.extensions.create 注册了 myPluginExtension 扩展,并且创建了一个 printExtension 任务来打印扩展中的配置值。
  3. 在应用插件的项目中使用配置扩展 在应用该插件的项目的 build.gradle.kts 文件中,可以这样配置:
    plugins {
        kotlin("jvm") version "1.6.21"
        id("com.example.my - kotlin - plugin")
    }
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        implementation(kotlin("stdlib - jdk8"))
    }
    
    myPluginExtension {
        customString = "new string"
        customInt = 20
    }
    
    执行 ./gradlew printExtension 任务,会输出:
    > Task :printExtension
    Custom string: new string
    Custom int: 20
    

与其他插件交互

  1. 检测其他插件是否应用 在插件中,我们可以检测项目是否应用了其他特定的插件。例如,要检测项目是否应用了 kotlin - jvm 插件,可以在 MyKotlinPlugin.kt 中这样做:
    package com.example.my - kotlin - plugin
    
    import org.gradle.api.Plugin
    import org.gradle.api.Project
    
    class MyKotlinPlugin : Plugin<Project> {
        override fun apply(target: Project) {
            val hasKotlinJvmPlugin = target.plugins.hasPlugin("kotlin - jvm")
            if (hasKotlinJvmPlugin) {
                target.logger.lifecycle("The project has the kotlin - jvm plugin applied.")
            } else {
                target.logger.lifecycle("The project does not have the kotlin - jvm plugin applied.")
            }
            target.logger.lifecycle("Project name: ${target.name}")
            target.logger.lifecycle("Project version: ${target.version}")
        }
    }
    
  2. 与其他插件任务交互 假设项目应用了 kotlin - jvm 插件,我们希望在 compileKotlin 任务之后执行我们的自定义任务。在 MyKotlinPlugin.kt 中修改如下:
    package com.example.my - kotlin - plugin
    
    import org.gradle.api.Plugin
    import org.gradle.api.Project
    import org.gradle.api.tasks.TaskProvider
    
    class MyKotlinPlugin : Plugin<Project> {
        override fun apply(target: Project) {
            val myCustomTask: TaskProvider<MyCustomTask> = target.tasks.register("myCustomTask", MyCustomTask::class.java)
            if (target.plugins.hasPlugin("kotlin - jvm")) {
                target.tasks.named("compileKotlin").configure {
                    it.finalizedBy(myCustomTask)
                }
            }
            target.logger.lifecycle("Project name: ${target.name}")
            target.logger.lifecycle("Project version: ${target.version}")
        }
    }
    
    这里通过 it.finalizedBy(myCustomTask) 使得 myCustomTaskcompileKotlin 任务完成后执行。

发布 Gradle 插件

发布到本地 Maven 仓库

  1. 配置发布相关信息 在插件项目的 build.gradle.kts 文件中添加发布到本地 Maven 仓库的配置:
    plugins {
        `maven - publish`
    }
    
    group = "com.example"
    version = "1.0.0"
    
    publishing {
        publications {
            create<MavenPublication>("maven") {
                from(components["java"])
            }
        }
        repositories {
            mavenLocal()
        }
    }
    
    这里配置了插件的组为 com.example,版本为 1.0.0,并通过 publishing 块指定发布到本地 Maven 仓库。
  2. 执行发布任务 在插件项目目录下执行 ./gradlew publishToMavenLocal 任务,Gradle 会将插件发布到本地 Maven 仓库(通常位于 ~/.m2/repository 目录下)。此时,其他项目就可以通过 mavenLocal() 仓库依赖这个插件。在其他项目的 build.gradle.kts 文件中可以这样应用:
    plugins {
        kotlin("jvm") version "1.6.21"
    }
    
    repositories {
        mavenLocal()
        mavenCentral()
    }
    
    dependencies {
        implementation(kotlin("stdlib - jdk8"))
    }
    
    apply(plugin = "com.example.my - kotlin - plugin")
    

发布到远程 Maven 仓库

  1. 配置远程仓库信息 如果要发布到远程 Maven 仓库,如 JCenter(虽然 JCenter 已停止服务,这里仅作示例,实际可选择其他仓库如 Maven Central),需要在 build.gradle.kts 中添加如下配置:
    plugins {
        `maven - publish`
        signing
    }
    
    group = "com.example"
    version = "1.0.0"
    
    publishing {
        publications {
            create<MavenPublication>("maven") {
                from(components["java"])
                groupId = "com.example"
                artifactId = "my - kotlin - plugin"
                version = "1.0.0"
                pom {
                    name.set("My Kotlin Plugin")
                    description.set("A custom Kotlin Gradle plugin.")
                    url.set("https://github.com/your - repo/your - plugin")
                    licenses {
                        license {
                            name.set("The Apache License, Version 2.0")
                            url.set("http://www.apache.org/licenses/LICENSE - 2.0.txt")
                        }
                    }
                    developers {
                        developer {
                            id.set("your - id")
                            name.set("Your Name")
                            email.set("your - email@example.com")
                        }
                    }
                    scm {
                        connection.set("scm:git:git://github.com/your - repo/your - plugin.git")
                        developerConnection.set("scm:git:ssh://git@github.com/your - repo/your - plugin.git")
                        url.set("https://github.com/your - repo/your - plugin")
                    }
                }
            }
        }
        repositories {
            maven {
                url = uri("https://jcenter.bintray.com")
                credentials {
                    username = project.properties["jcenterUsername"] as String?
                    password = project.properties["jcenterPassword"] as String?
                }
            }
        }
    }
    
    signing {
        useInMemoryPgpKeys(
            project.properties["pgpKey"] as String?,
            project.properties["pgpSecret"] as String?
        )
        sign(publishing.publications["maven"])
    }
    
    这里配置了发布到 JCenter 的相关信息,包括仓库 URL、认证信息,同时配置了插件的 POM 文件信息以及签名信息。
  2. 执行发布任务 执行 ./gradlew publish 任务,Gradle 会将插件发布到远程 Maven 仓库。注意,需要提前在项目的 gradle.properties 文件中配置 jcenterUsernamejcenterPasswordpgpKeypgpSecret 等信息。发布成功后,其他项目就可以通过远程仓库依赖该插件。例如,在其他项目的 build.gradle.kts 文件中:
    plugins {
        kotlin("jvm") version "1.6.21"
    }
    
    repositories {
        jcenter()
        mavenCentral()
    }
    
    dependencies {
        implementation(kotlin("stdlib - jdk8"))
    }
    
    apply(plugin = "com.example.my - kotlin - plugin")
    

通过以上内容,我们全面地了解了 Kotlin 中 Gradle 插件开发与自定义任务的相关知识,从基础的插件创建到复杂的插件发布,希望这些内容能帮助你在 Kotlin 项目构建中更好地发挥 Gradle 插件的强大功能。