ama*_*eus 10 gradle kotlin-multiplatform
我正在开发一个 Kotlin 多平台项目,该项目是一个为 iOS 和 Android 应用程序提供功能的 SDK。
在我们的代码中,build.gradle.kts我们希望在 iOS 和 Android 之间的公共代码共享代码中访问几个变量。
作为一名 Android 开发人员,我在 Android 项目中通常会这样做:
android {
...
defaultConfig {
...
buildConfigField "String", "SOME_VARIABLE", '"' + SOME_VARIABLE_IN_GRADLE_FILES + '"'
...
}
...
}
Run Code Online (Sandbox Code Playgroud)
然后我可以在代码中访问它:
val someVariable = BuildConfig.SOME_VARIABLE
Run Code Online (Sandbox Code Playgroud)
如何才能使类似的东西在 Kotlin Mulitplatform 项目中工作,因为BuildConfig这不是公共共享代码库中认可的东西。
在搜索这个主题的解决方案后,我还没有找到任何相关的答案,但是我的 googlefoo 技能可能还不够......
aSe*_*emy 15
@Evgeny 提供的答案将解决问题,但我认为这是学习如何在纯 Gradle 中解决此问题的一个很好的例子。即使您想使用插件,了解 Gradle 的工作原理也可以帮助您了解如何自定义任何插件或 Gradle 行为。
有几个 Gradle 实用程序可用于从构建属性生成代码。
TextResourceFactory可以动态创建文件。注意惰性配置也很重要。仅应在必要时才生成该文件。
任务是在 Gradle 中定义工作的方式,因此让我们创建一个将生成文件作为输出的任务。Sync是一个很好的任务类型。Sync会将任意数量的文件复制到一个目录中。
// build.gradle.kts
val buildConfigGenerator by tasks.registering(Sync::class) {
// from(...) // no input files yet
// the target directory
into(layout.buildDirectory.dir("generated-src/kotlin"))
}
Run Code Online (Sandbox Code Playgroud)
如果您运行./gradlew buildConfigGenerator,则任务将运行,但唯一发生的事情是./build/generated-src/kotlin/创建一个空目录。因此,让我们添加一个文件作为输入。
TextResouceFactory是一个鲜为人知的工具,可以动态创建文本文件。(包括从 URL 下载文本文件,这可以派上用场!)
让我们使用它创建一个 Kotlin 文件。
// build.gradle.kts
val buildConfigGenerator by tasks.registering(Sync::class) {
from(
resources.text.fromString(
"""
|package my.project
|
|object BuildConfig {
| const val PROJECT_VERSION = "${project.version}"
|}
|
""".trimMargin()
)
) {
rename { "BuildConfig.kt" } // set the file name
into("my/project/") // change the directory to match the package
}
into(layout.buildDirectory.dir("generated-src/kotlin/"))
}
Run Code Online (Sandbox Code Playgroud)
请注意,我必须重命名该文件(TextResourceFactory将生成一个随机名称),并将目录设置为匹配package my.project。
现在如果你运行./gradlew buildConfigGenerator它实际上会生成一个文件!
// ./build/generated-src/kotlin/BuildConfig.kt
package my.project
object BuildConfig {
const val PROJECT_VERSION = "0.0.1"
}
Run Code Online (Sandbox Code Playgroud)
然而,还有两件事需要解决。
./build/generated-src/kotlin/源目录。我们可以一次性解决这两个问题!
您可以通过 Kotlin Multiplatform 插件 DSL 将新的源目录添加到 Kotlin SourceSetkotlin.srcDir()
// build.gradle.kts
plugins {
kotlin("multiplatform") version "1.7.22"
}
kotlin {
sourceSets {
val commonMain by getting {
kotlin.srcDir(/* add the generate source directory here... */)
}
}
}
Run Code Online (Sandbox Code Playgroud)
我们可以硬编码kotlin.srcDir(layout.buildDirectory.dir("generated-src/kotlin/"))- 但现在我们还没有告诉 Gradle 我们的任务!我们仍然需要手动运行它。
幸运的是,我们可以两全其美。感谢 Gradle 的 Provider API,任务可以转换为 file-provider。
// build.gradle.kts
kotlin {
sourceSets {
val commonMain by getting {
kotlin.srcDir(
// convert the task to a file-provider
buildConfigGenerator.map { it.destinationDir }
)
}
}
}
Run Code Online (Sandbox Code Playgroud)
(请注意,由于buildConfigGenerator是使用tasks.registering()其类型 is创建的TaskProvider,因此使用 类型创建的任务则不然tasks.creating()。)
generatedSourceDirProvider将延迟提供生成的目录,并且因为它是从任务映射的,所以 Gradle 知道每当使用源集进行编译时,它都需要运行连接的任务。commonMain
要对此进行测试,请运行./gradlew clean. 构建目录消失了,包括生成的文件。现在运行./gradlew assemble- Gradle 将自动运行generatedSourceDirProvider。魔法!
当我第一次在 IntelliJ 中打开项目时,没有生成源代码,这有点烦人。我可以添加gradle-idea-ext-plugin,并使 IntelliJbuildConfigGenerator在 Gradle 同步上触发。
在此示例中,我硬编码了project.version. 但是如果项目版本是动态的怎么办?
在这种情况下,我们需要使用一个提供者,它可以映射到一个文件。
// build.gradle.kts
val buildConfigGenerator by tasks.registering(Sync::class) {
// create a provider for the project version
val projectVersionProvider: Provider<String> = provider { project.version.toString() }
// map the project version into a file
val buildConfigFileContents: Provider<TextResource> =
projectVersionProvider.map { version ->
resources.text.fromString(
"""
|package my.project
|
|object BuildConfig {
| const val PROJECT_VERSION = "$version"
|}
|
""".trimMargin()
)
}
// Gradle accepts file providers as Sync inputs
from(buildConfigFileContents) {
rename { "BuildConfig.kt" }
into("my/project/")
}
into(layout.buildDirectory.dir("generated-src/kotlin/"))
}
Run Code Online (Sandbox Code Playgroud)
如果您想从多个属性生成一个文件怎么办?在这种情况下,我要么
MapProperty,将所有属性设置到其中,然后(因为MapProperty是 Gradle 提供程序)将映射.map { }放入文件中您可以使用com.github.gmazzo.buildconfiggradle 插件来实现此目的(github)。
您可以在里面找到 KMM 项目的示例。
基本上你应该添加:
plugins {
kotlin("multiplatform")
// other plugins
id("com.github.gmazzo.buildconfig") version "<latest>"
}
// ...
buildConfig {
// common config
buildConfigField("String", "COMMON_VALUE", "\"aCommonValue\"")
// for specific source set
sourceSets.named<BuildConfigSourceSet>("jvmMain") {
buildConfigField("String", "PLATFORM", "\"jvm\"")
buildConfigField("String", "JVM_VALUE", "\"JvmValue\"")
}
}
Run Code Online (Sandbox Code Playgroud)
你也可以看看com.codingfeline.buildkonfig(github)它有类似的API
| 归档时间: |
|
| 查看次数: |
2264 次 |
| 最近记录: |