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

Kotlin中的构建工具Gradle高级配置

2024-03-066.3k 阅读

Gradle简介

Gradle 是一个基于 Apache Ant 和 Apache Maven 概念的项目自动化构建工具,它结合了二者的优点,采用了灵活的基于 Groovy 的 DSL (领域特定语言)来声明项目设置,抛弃了基于 XML 的各种繁琐配置。在 Kotlin 开发中,Gradle 作为构建工具,能帮助开发者更高效地管理项目依赖、构建脚本以及进行自动化构建等操作。

Gradle的基础配置

在 Kotlin 项目中,Gradle 的基础配置通常包含在项目根目录下的 build.gradle.kts(Kotlin DSL 版本)或 build.gradle(Groovy DSL 版本)文件中。以下是一个简单的 Kotlin 项目的基础 Gradle 配置示例(Kotlin DSL):

plugins {
    kotlin("jvm") version "1.6.21"
}

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

repositories {
    mavenCentral()
}

dependencies {
    implementation(kotlin("stdlib-jdk8"))
}

在上述配置中:

  • plugins 块用于应用插件,这里应用了 Kotlin JVM 插件,指定了 Kotlin 的版本为 1.6.21
  • group 定义了项目的组,version 定义了项目的版本。
  • repositories 块指定了依赖仓库,这里使用了 Maven Central 仓库。
  • dependencies 块用于声明项目的依赖,implementation 配置表示实现依赖,这里引入了 Kotlin 标准库(适用于 JDK 8)。

Gradle高级配置之自定义属性

在实际项目开发中,我们经常需要在 Gradle 配置中使用一些自定义的属性,比如版本号、服务器地址等,这样可以方便地统一管理和修改相关配置。

定义自定义属性

build.gradle.kts 文件中,可以在根目录下定义属性,例如:

val myCustomVersion: String by extra("1.0.0")
val serverUrl: String by extra("http://example.com/api")

上述代码定义了两个自定义属性 myCustomVersionserverUrl,并分别赋予了初始值。

使用自定义属性

定义好属性后,可以在 dependencies 或其他需要的地方使用,例如:

dependencies {
    implementation("com.example:my-library:$myCustomVersion")
}

这样,当 myCustomVersion 的值发生变化时,所有依赖该版本的库都会自动更新。

Gradle高级配置之多模块项目

大型项目往往会被拆分成多个模块,Gradle 对多模块项目提供了强大的支持。

创建多模块项目结构

假设我们要创建一个包含 app 模块和 library 模块的 Kotlin 项目,项目结构如下:

my-project/
├── app/
│   ├── build.gradle.kts
│   └── src/
├── library/
│   ├── build.gradle.kts
│   └── src/
└── build.gradle.kts

根目录 build.gradle.kts 配置

在根目录的 build.gradle.kts 文件中,需要声明子模块:

plugins {
    `kotlin-multiplatform` version "1.6.21" apply false
}

include("app", "library")

这里应用了 kotlin-multiplatform 插件,但设置 apply false 表示不在根项目应用,而是在子模块中应用。include 方法声明了两个子模块 applibrary

子模块 build.gradle.kts 配置

library 模块为例,其 build.gradle.kts 配置如下:

plugins {
    kotlin("jvm")
}

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

repositories {
    mavenCentral()
}

dependencies {
    implementation(kotlin("stdlib-jdk8"))
}

app 模块的配置类似,但可能会有不同的依赖,并且通常会依赖 library 模块:

plugins {
    kotlin("jvm")
}

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

repositories {
    mavenCentral()
}

dependencies {
    implementation(project(":library"))
    implementation(kotlin("stdlib-jdk8"))
}

通过 implementation(project(":library")) 来表示 app 模块依赖 library 模块。

Gradle高级配置之依赖管理

依赖版本管理

在大型项目中,管理众多依赖的版本是一项复杂的任务。Gradle 提供了一些方式来简化版本管理。

  1. 使用 ext 块统一管理版本:在 build.gradle.kts 文件中,可以使用 ext 块来定义版本变量,例如:
ext {
    kotlinVersion = "1.6.21"
    okhttpVersion = "4.9.1"
}

dependencies {
    implementation(kotlin("stdlib-jdk8", kotlinVersion))
    implementation("com.squareup.okhttp3:okhttp:$okhttpVersion")
}
  1. 使用 versions 插件:可以通过引入 versions 插件来更方便地管理依赖版本。首先在根目录的 build.gradle.kts 中应用插件:
plugins {
    id("com.github.ben-manes.versions") version "0.42.0"
}

然后可以通过 dependencyUpdates 任务来检查依赖的最新版本,并在需要时更新版本号。

排除依赖传递

有时候,项目依赖的某个库会传递引入一些不需要的依赖,这时候可以使用 exclude 来排除这些传递依赖。例如:

dependencies {
    implementation("com.example:my-library:1.0.0") {
        exclude(group = "com.unwanted.group", module = "unwanted-module")
    }
}

上述代码表示在引入 com.example:my-library:1.0.0 库时,排除 com.unwanted.group:unwanted-module 这个传递依赖。

Gradle高级配置之构建脚本自定义

自定义构建任务

Gradle 允许开发者自定义构建任务,以满足项目特定的需求。以下是一个简单的自定义任务示例,用于在构建过程中输出一些信息:

tasks.register("customTask") {
    doLast {
        println("This is a custom task.")
    }
}

上述代码定义了一个名为 customTask 的任务,当执行 ./gradlew customTask 命令时,会输出 This is a custom task.

任务依赖

可以定义任务之间的依赖关系,例如,我们希望在执行 customTask 之前先执行 clean 任务:

tasks.register("customTask") {
    dependsOn(tasks.clean)
    doLast {
        println("This is a custom task.")
    }
}

这样,当执行 ./gradlew customTask 时,Gradle 会先执行 clean 任务,然后再执行 customTask

Gradle高级配置之构建变体

在 Android 开发中,构建变体是非常常用的概念,其实在 Kotlin JVM 项目中也可以通过类似的方式实现不同的构建配置。

构建类型

可以定义不同的构建类型,比如 debugrelease,并为每种构建类型配置不同的属性。以下是一个简单的示例:

val buildTypes = mutableMapOf<String, Map<String, Any>>()
buildTypes["debug"] = mapOf("isDebuggable" to true)
buildTypes["release"] = mapOf("isDebuggable" to false)

tasks.register<JavaExec>("run") {
    val buildType = project.findProperty("buildType") as? String ?: "debug"
    val properties = buildTypes[buildType]
    if (properties != null) {
        systemProperties(properties)
    }
    mainClass.set("com.example.MainKt")
}

上述代码定义了 debugrelease 两种构建类型,并在 run 任务中根据 buildType 属性来设置不同的系统属性。执行 ./gradlew run -PbuildType=release 时,会使用 release 构建类型的配置。

产品风味

类似于 Android 中的产品风味,在 Kotlin 项目中也可以定义不同的产品风味,以满足不同场景的需求。例如,我们可以定义 freepro 两种产品风味:

val productFlavors = mutableMapOf<String, Map<String, Any>>()
productFlavors["free"] = mapOf("featureLevel" to "basic")
productFlavors["pro"] = mapOf("featureLevel" to "advanced")

tasks.register<JavaExec>("run") {
    val flavor = project.findProperty("flavor") as? String ?: "free"
    val properties = productFlavors[flavor]
    if (properties != null) {
        systemProperties(properties)
    }
    mainClass.set("com.example.MainKt")
}

执行 ./gradlew run -Pflavor=pro 时,会使用 pro 产品风味的配置。

Gradle高级配置之与持续集成(CI)结合

在现代软件开发流程中,持续集成是非常重要的环节。Gradle 可以很好地与常见的 CI 工具(如 Jenkins、GitLab CI/CD、GitHub Actions 等)结合。

GitHub Actions 示例

以下是一个简单的 .github/workflows/build.yml 文件示例,用于在 GitHub Actions 中使用 Gradle 构建 Kotlin 项目:

name: Kotlin CI

on:
  push:
    branches:
      - main
  pull_request:

jobs:
  build:
    runs-on: ubuntu - latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Set up JDK 11
        uses: actions/setup-java@v2
        with:
          java-version: '11'
          distribution: 'adopt'

      - name: Build with Gradle
        uses: gradle/gradle-build-action@v2
        with:
          arguments: build

上述配置表示当 main 分支有推送或者有拉取请求时,在 Ubuntu 最新环境中,使用 JDK 11,通过 Gradle 执行 build 任务。

GitLab CI/CD 示例

.gitlab-ci.yml 文件中,可以这样配置:

image: gradle:7.3.3-jdk11

stages:
  - build

build:
  stage: build
  script:
    - gradle build

这个配置使用 gradle:7.3.3-jdk11 镜像,在 build 阶段执行 gradle build 命令来构建项目。

Gradle高级配置之性能优化

并行构建

Gradle 支持并行构建,通过并行执行任务可以显著提高构建速度。在 gradle.properties 文件中添加以下配置可以启用并行构建:

org.gradle.parallel=true

增量构建

Gradle 会自动尝试进行增量构建,只重新构建那些发生变化的部分。为了更好地利用增量构建,开发者应该确保任务的输入和输出是明确的。例如,在自定义任务中,可以通过 inputsoutputs 来声明任务的输入和输出,以便 Gradle 能够准确判断任务是否需要重新执行:

tasks.register("customTask") {
    inputs.file("src/main/kotlin/com/example/inputFile.kt")
    outputs.file("build/output/customOutput.txt")
    doLast {
        // 任务逻辑
    }
}

构建缓存

Gradle 支持构建缓存,可以将构建结果缓存起来,下次构建时如果相关输入没有变化,就可以直接使用缓存的结果。在 gradle.properties 文件中启用构建缓存:

org.gradle.caching=true

此外,还可以配置远程构建缓存,例如使用 GitHub Actions 的缓存服务:

- name: Set up Gradle caches
  uses: actions/cache@v2
  with:
    path: |
      ~/.gradle/caches
      ~/.gradle/wrapper
    key: ${{ runner.os }}-gradle-${{ hashFiles('build.gradle.kts') }}
    restore-keys: |
      ${{ runner.os }}-gradle-

通过上述配置,可以有效地提高 Gradle 构建的性能,减少构建时间。

Gradle高级配置之插件开发

在某些情况下,项目可能需要自定义 Gradle 插件来满足特定的需求。以下是一个简单的自定义 Gradle 插件的示例。

创建插件项目

首先创建一个新的 Gradle 项目,项目结构如下:

my-plugin/
├── src/
│   └── main/
│       ├── groovy/
│       │   └── com/
│       │       └── example/
│       │           └── MyPlugin.groovy
│       └── resources/
│           └── META-INF/
│               └── gradle-plugins/
│                   └── com.example.my-plugin.properties
└── build.gradle.kts

编写插件代码

MyPlugin.groovy 文件中编写插件逻辑:

package com.example

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

class MyPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.task('myCustomTask') {
            doLast {
                println 'This is a task from my custom plugin.'
            }
        }
    }
}

上述代码定义了一个插件,该插件为项目添加了一个名为 myCustomTask 的任务。

配置插件描述文件

com.example.my-plugin.properties 文件中配置插件描述:

implementation-class=com.example.MyPlugin

构建和发布插件

build.gradle.kts 文件中配置插件的构建和发布:

plugins {
    `groovy-gradle-plugin`
    `maven-publish`
}

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

repositories {
    mavenCentral()
}

dependencies {
    implementation(gradleApi())
    implementation(localGroovy())
}

publishing {
    publications {
        create<MavenPublication>("maven") {
            from(components["java"])
        }
    }
    repositories {
        maven {
            url = uri("$buildDir/repository")
        }
    }
}

通过上述配置,可以构建插件并发布到本地仓库 $buildDir/repository

使用自定义插件

在其他项目的 build.gradle.kts 文件中,可以这样使用自定义插件:

plugins {
    id("com.example.my-plugin") version "1.0.0" apply true
}

然后就可以执行 ./gradlew myCustomTask 来运行自定义插件中的任务。

总结

Gradle 在 Kotlin 项目开发中扮演着至关重要的角色,通过深入了解和掌握其高级配置,开发者可以更好地管理项目依赖、优化构建流程、实现自定义构建逻辑等。无论是小型项目还是大型企业级项目,合理运用 Gradle 的高级特性都能显著提高开发效率和项目质量。从自定义属性到多模块项目管理,从依赖管理到构建脚本自定义,再到与 CI 结合以及性能优化和插件开发,Gradle 提供了丰富的功能和灵活的配置方式,满足不同场景下的项目需求。在实际开发过程中,开发者应根据项目的具体情况,不断探索和优化 Gradle 配置,以打造高效、稳定的开发环境。