BuildKonfig:基于 Kotlin 的构建配置生成工具项目

BuildConfig for Kotlin Multiplatform Project

分支5Tags40
文件最后提交记录最后更新时间
2 个月前
1 个月前
4 年前
3 个月前
1 个月前
1 个月前
2 个月前
3 个月前
4 个月前
2 个月前
4 个月前
2 个月前
4 个月前
7 年前
2 个月前
5 年前
2 个月前
2 个月前
2 个月前
2 个月前
4 个月前
4 个月前
4 年前

BuildKonfig

Maven Central

适用于 Kotlin Multiplatform 和 Kotlin/JVM 项目的 BuildConfig。
目前支持从 gradle 文件嵌入值。

目录

动机

从 Android/iOS 或其他平台代码传递值虽然可行,但过程繁琐。
在 Android 中设置从属性读取值并添加到 BuildConfig,然后在 iOS 中执行类似操作?
我更希望只需配置一次。

使用方法

要求

  • Kotlin 2.1.0 或更高版本
  • 已应用以下任一插件的项目:Kotlin Multiplatform 或 Kotlin/JVM(通过 KMP 的 js() 目标使用 Kotlin/JS)
  • Gradle 8 或更高版本

Gradle 配置

简单配置

Kotlin DSL
import com.codingfeline.buildkonfig.compiler.FieldSpec.Type.STRING

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.3.20")
        classpath("com.codingfeline.buildkonfig:buildkonfig-gradle-plugin:latest_version")
    }
}

plugins {
    kotlin("multiplatform")
    id("com.codingfeline.buildkonfig")
}

kotlin {
    // your target config...
    androidTarget()
    iosX64('ios')
}

buildkonfig {
    packageName = "com.example.app"
    // objectName = "YourAwesomeConfig"
    // exposeObjectWithName = "YourAwesomePublicConfig"

    defaultConfigs {
        buildConfigField(STRING, "name", "value")
    }
}
Groovy DSL
buildScript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:2.3.20'
        classpath 'com.codingfeline.buildkonfig:buildkonfig-gradle-plugin:latest_version'
    }
}

apply plugin: 'org.jetbrains.kotlin.multiplatform'
apply plugin: 'com.codingfeline.buildkonfig'

kotlin {
    // your target config...
    androidTarget()
    iosX64('ios')
}

buildkonfig {
    packageName = 'com.example.app'
    // objectName = 'YourAwesomeConfig'
    // exposeObjectWithName = 'YourAwesomePublicConfig'

    defaultConfigs {
        buildConfigField 'STRING', 'name', 'value'
    }
}
  • packageName 设置 BuildKonfig 所在的包名。必填项
  • objectName 设置生成的对象名称。默认为 BuildKonfig
  • exposeObjectWithName 设置生成的对象名称,并将其设为公开。
  • defaultConfigs 设置您希望共有的值。如果省略,将记录警告并跳过代码生成。

要生成 BuildKonfig 文件,请运行 generateBuildKonfig 任务。
此任务将在执行 Kotlin 编译任务时自动运行。

上述配置将生成以下简单对象。

// commonMain
package com.example.app

internal object BuildKonfig {
    val name: String = "value"
}

配置 target 相关值

如果您想根据目标更改值,可以使用 targetConfigs 来定义目标相关值。

Kotlin DSL
import com.codingfeline.buildkonfig.compiler.FieldSpec.Type.STRING

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.3.20")
        classpath("com.codingfeline.buildkonfig:buildkonfig-gradle-plugin:latest_version")
    }
}

plugins {
    kotlin("multiplatform")
    id("com.codingfeline.buildkonfig")
}

kotlin {
    // your target config...
    androidTarget()
    iosX64('ios')
}

buildkonfig {
    packageName = "com.example.app"

    // default config is required
    defaultConfigs {
        buildConfigField(STRING, "name", "value")
    }

    targetConfigs {
        // names in create should be the same as target names you specified
        create("android") {
            buildConfigField(STRING, "name2", "value2")
            buildConfigField(STRING, "nullableField", "NonNull-value", nullable = true)
        }

        create("ios") {
            buildConfigField(STRING, "name", "valueForNative")
        }
    }
}
Groovy DSL
buildScript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:2.3.20'
        classpath 'com.codingfeline.buildkonfig:buildkonfig-gradle-plugin:latest_version'
    }
}

apply plugin: 'org.jetbrains.kotlin.multiplatform'
apply plugin: 'com.codingfeline.buildkonfig'

kotlin {
    // your target config...
    androidTarget()
    iosX64('ios')
}

buildkonfig {
    packageName = 'com.example.app'

    // default config is required
    defaultConfigs {
        buildConfigField 'STRING', 'name', 'value'
        buildConfigField 'STRING', 'nullableField', null, nullable: true
    }

    targetConfigs {
        // this name should be the same as target names you specified
        android {
            buildConfigField 'STRING', 'name2', 'value2'
            buildConfigField 'STRING', 'nullableField', 'NonNull-value', nullable: true
        }

        ios {
            buildConfigField 'STRING', 'name', 'valueForNative'
        }
    }
}
  • packageName
    • 设置 BuildKonfig 放置的包名。必填项
  • objectName
    • 设置生成对象的名称。默认为 BuildKonfig
  • exposeObjectWithName
    • 设置生成对象的名称,并将其设为公开。
  • defaultConfigs
    • 设置您希望共有的值。如果省略,将记录警告并跳过代码生成。
  • targetConfigs
    • 以闭包形式设置特定于目标的值。您可以覆盖在 defaultConfigs 中指定的值。
  • buildConfigField(type: String, name: String, value: String)
    • 添加新值或覆盖现有值。
  • buildConfigField(type: String, name: String, value: String, nullable: Boolean = false, const: Boolean = false)
    • 除上述方法外,此方法还可以配置 nullable(可空)和 const(常量)声明。

Note

当存在 targetConfigs 时,BuildKonfig 会生成为 expect/actual 形式。K2 编译器(Kotlin 2.x)不允许 expect const val,因此即使您设置 const = true,公共端声明也会生成为普通 val。每个目标的 actual 声明仍然使用 actual const val,因此该值在特定于目标的源代码集中是编译时常量 — 但公共代码不能将其作为编译时常量引用(例如,在需要常量的 when 分支中,或注解参数中)。生成时会为受影响的字段记录警告。

上述配置将生成以下代码。

// commonMain
package com.example.app

internal expect object BuildKonfig {
    val name: String
    val nullableField: String?
}
// androidMain
package com.example.app

internal actual object BuildKonfig {
    actual val name: String = "value"
    actual val nullableField: String? = "NonNull-value"
    val name2: String = "value2"
}
// iosMain
package com.example.app

internal actual object BuildKonfig {
    actual val name: String = "valueForNative"
    actual val nullableField: String? = null
}

非多平台项目

BuildKonfig 同样适用于独立的 Kotlin/JVM 项目。 使用 org.jetbrains.kotlin.jvm 插件替代多平台插件,并使用相同的 buildkonfig { ... } 配置块。 对于 Kotlin/JS,请使用带有 js() 目标的 Kotlin Multiplatform 插件——独立的 org.jetbrains.kotlin.js 插件已在 Kotlin 2.4.0 中移除。

Kotlin DSL
import com.codingfeline.buildkonfig.compiler.FieldSpec.Type.STRING

plugins {
    kotlin("jvm")
    id("com.codingfeline.buildkonfig")
}

buildkonfig {
    packageName = "com.example.app"

    defaultConfigs {
        buildConfigField(STRING, "name", "value")
    }
}
Groovy DSL
apply plugin: 'org.jetbrains.kotlin.jvm'
apply plugin: 'com.codingfeline.buildkonfig'

buildkonfig {
    packageName = 'com.example.app'

    defaultConfigs {
        buildConfigField 'STRING', 'name', 'value'
    }
}

单个具体对象会生成到 main 源代码集中——不存在 expect/actual 分离,因为只有一个目标。

// src/main/kotlin (generated)
package com.example.app

internal object BuildKonfig {
    val name: String = "value"
}

defaultConfigs 块(包括 flavor)得到完全支持。对于单目标项目,targetConfigs 没有意义;如果声明了它们,会记录一条警告并忽略它们。

产品 Flavor?

可以(某种程度上)。
Kotlin 多平台项目不支持产品 flavor。项目的 Kotlin/Native 部分有 release/debug 的区别,但这不是全局的。
因此,为了模拟 Android 的产品 flavor 功能,我们需要提供额外的属性来确定 flavor。

gradle.properties 中指定默认 flavor。

# ROOT_DIR/gradle.properties
buildkonfig.flavor=dev
Kotlin DSL
import com.codingfeline.buildkonfig.compiler.FieldSpec.Type.STRING
import com.codingfeline.buildkonfig.gradle.TargetConfigDsl

buildkonfig {
    packageName = "com.example.app"

    // default config is required
    defaultConfigs {
        buildConfigField(STRING, "name", "value")
    }
    // flavor is passed as a first argument of defaultConfigs
    defaultConfigs("dev") {
        buildConfigField(STRING, "name", "devValue")
    }

    targetConfigs {
        create("android") {
            buildConfigField(STRING, "name2", "value2")
        }

        create("ios") {
            buildConfigField(STRING, "name", "valueIos")
        }
    }
    // flavor is passed as a first argument of targetConfigs
    targetConfigs("dev") {
        create("ios") {
            buildConfigField(STRING, "name", "devValueIos")
        }
    }
}
Groovy DSL
// ./kmp_project/build.gradle

buildkonfig {
    packageName = 'com.example.app'

    // default config is required
    defaultConfigs {
        buildConfigField 'STRING', 'name', 'value'
    }
    // flavor is passed as a first argument of defaultConfigs
    defaultConfigs("dev") {
        buildConfigField 'STRING', 'name', 'devValue'
    }

    targetConfigs {
        android {
            buildConfigField 'STRING', 'name2', 'value2'
        }

        ios {
            buildConfigField 'STRING', 'name', 'valueIos'
        }
    }
    // flavor is passed as a first argument of targetConfigs
    targetConfigs("dev") {
        ios {
            buildConfigField 'STRING', 'name', 'devValueIos'
        }
    }
}

在开发阶段,你可以随意修改 gradle.properties 中的值。
在 CI 环境中,你可以通过 CLI 传入值,例如 $ ./gradlew build -Pbuildkonfig.flavor=release

覆盖值

如果你在多个 defaultConfigs 和 targetConfigs 中配置了相同的字段,那么带有 flavor 的 targetConfigs 优先级最高。

从左到右,优先级依次降低。

Flavored TargetConfig > TargetConfig > Flavored DefaultConfig > DefaultConfig

HMPP 支持

也称为“中间源代码集”。(详见在平台间共享代码。)
BuildKonfig 支持 HMPP,但存在一些限制。

当你为中间源代码集添加 targetConfigs 时,不能为其子源代码集定义其他 targetConfigs。

例如,假设你有如下的源代码集结构。

- commonMain
  - appMain
    - androidMain
    - desktopMain
      - macosArm64Main
      - linuxX64Main
      - mingwX64Main
  - jsCommonMain
    - browserMain
    - nodeMain
  - iosMain
    - iosArm64Main
    - iosX64Main

如果你为 appMain 添加了 targetConfigs,就不能再为 androidMaindesktopMaindesktopMain 的子级添加配置了。这是因为 BuildKonfig 使用 expect/actual 为每个 BuildKonfig 对象提供不同的值。当你为 appMain 提供配置时,BuildKonfig 对象的 actual 声明会在 appMain 中创建。因此,在子 SourceSet 中添加任何额外的 actual 声明都会导致编译时错误。

支持的类型

  • String
  • Int
  • Long
  • Float
  • Boolean

试用示例

有两个示例:samplesample-kts。顾名思义,sample-kts 是 Kotlin DSL 示例,另一个是传统的 Groovy DSL 示例。

可以查看 ./sample 目录。

# Publish the latest version of the plugin to test maven repository(./build/localMaven)
$ ./gradlew publishAllPublicationsToTestMavenRepository -PRELEASE_SIGNING_ENABLED=false

# Try out the samples.
# BuildKonfig will be generated in ./sample/build/buildkonfig
$ ./gradlew -p sample generateBuildKonfig

项目介绍

Kotlin 多平台项目的 BuildConfig【此简介由AI生成】

定制我的领域
81.21 K47访问 GitHub