如何在IntelliJ中为Ktor项目配置Dev/Sit/Prod多构建变体
为Ktor项目实现多环境构建变体(Dev/Sit/Prod)并加载密钥到配置类
我有一个Ktor项目,想要实现以下配置:创建Dev、Sit、Prod三种构建变体,并且为每个变体把密钥加载到类似Android BuildConfig的类中,这样就能动态选择不同的变体。下面是我在Android Studio中为Android应用实现该功能的可行示例,以及我当前Ktor项目的build.gradle.kts文件:
Android端实现示例代码
plugins { alias(libs.plugins.android.application) alias(libs.plugins.jetbrains.kotlin.android) alias(libs.plugins.jetbrainsCompose) alias(libs.plugins.compose.compiler) alias(libs.plugins.ksp) id("org.jetbrains.kotlin.plugin.serialization") } val secretsFileDev = rootProject.file("secrets.dev.properties") val secretsFileSit = rootProject.file("secrets.sit.properties") val secretsFileProd = rootProject.file("secrets.properties") val devProperties = Properties().apply { load(secretsFileDev.inputStream()) } val sitProperties = Properties().apply { load(secretsFileSit.inputStream()) } val prodProperties = Properties().apply { load(secretsFileProd.inputStream()) } val code = 1 val name = "1.0.0" android { namespace = "com.myapp" compileSdk = 34 defaultConfig { applicationId = "com.myapp" manifestPlaceholders["hostName"] = prodProperties["hostName"].toString() minSdk = 24 targetSdk = 34 versionCode = code versionName = name testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { useSupportLibrary = true } manifestPlaceholders["hostName"] = prodProperties["hostName"].toString() } flavorDimensions.add("environment") productFlavors { create("dev") { dimension = "environment" applicationIdSuffix = ".dev" versionNameSuffix = "-dev" loadProperties(devProperties, ::buildConfigField) } create("sit") { dimension = "environment" applicationIdSuffix = ".sit" versionNameSuffix = "-sit" loadProperties(sitProperties, ::buildConfigField) } create("prod") { dimension = "environment" applicationIdSuffix = ".prod" versionNameSuffix = "-prod" loadProperties(prodProperties, ::buildConfigField) } } buildTypes { getByName("debug") { applicationIdSuffix = ".debug" isDebuggable = true } getByName("release") { isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } buildFeatures { compose = true buildConfig = true viewBinding = true } applicationVariants.all { variant -> variant.outputs.all { output -> if (output is com.android.build.gradle.internal.api.ApkVariantOutputImpl) { if (variant.buildType.isDebuggable) { output.outputFileName = "myapp${variant.versionName}(${variant.versionCode}).apk" } else { output.outputFileName = "myapp-${variant.versionName}.apk" } } true } } } /** * 动态将属性加载到buildConfigFields中 */ fun loadProperties(properties: Properties, buildConfigField: (String, String, String) -> Unit) { buildConfigField("String", "baseUrl", properties["baseUrl"].toString()) buildConfigField("String", "API_KEY", properties["API_KEY"].toString()) buildConfigField("String", "GCP_API_KEY", properties["GCP_API_KEY"].toString()) } dependencies { /** 依赖项省略 */ }
当前Ktor项目的build.gradle.kts
val exposedVersion: String by project val h2Version: String by project val hikariCPVersion: String by project val koinVersion: String by project val kotlinVersion: String by project val ktorVersion: String by project val logbackVersion: String by project val mySQLVersion: String by project plugins { kotlin("jvm") version "2.0.10" id("io.ktor.plugin") version "2.3.12" id("org.jetbrains.kotlin.plugin.serialization") version "2.0.10" } group = "com.myktor-backend" version = "0.0.1" application { mainClass.set("com.myktor-backended.ApplicationKt") val isDevelopment: Boolean = project.ext.has("development") applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment") } repositories { mavenCentral() } dependencies { /** 依赖项省略 */ }
Ktor项目的实现方案
1. 创建环境属性文件
在项目根目录创建三个属性文件,分别对应不同环境:
secrets.dev.properties(开发环境)secrets.sit.properties(测试环境)secrets.prod.properties(生产环境)
每个文件存放对应环境的敏感配置,示例内容:
baseUrl=http://dev.example.com/api API_KEY=dev_abc123xyz GCP_API_KEY=dev_gcp_789qwe
2. 修改build.gradle.kts配置
更新Gradle脚本,实现环境变体识别、属性加载和配置类生成:
val exposedVersion: String by project val h2Version: String by project val hikariCPVersion: String by project val koinVersion: String by project val kotlinVersion: String by project val ktorVersion: String by project val logbackVersion: String by project val mySQLVersion: String by project plugins { kotlin("jvm") version "2.0.10" id("io.ktor.plugin") version "2.3.12" id("org.jetbrains.kotlin.plugin.serialization") version "2.0.10" // 引入kapt用于代码生成 kotlin("kapt") version "2.0.10" } group = "com.myktor-backend" version = "0.0.1" // 定义支持的环境列表 val environments = listOf("dev", "sit", "prod") // 预加载各环境的属性文件 val envPropsMap = environments.associateWith { env -> val propFile = rootProject.file("secrets.$env.properties") java.util.Properties().apply { if (propFile.exists()) load(propFile.inputStream()) } } // 为每个环境创建配置类生成任务 environments.forEach { env -> val taskName = "generate${env.replaceFirstChar(Char::uppercase)}BuildConfig" tasks.register<JavaExec>(taskName) { group = "build" description = "生成${env.uppercase()}环境的BuildConfig类" classpath = sourceSets["main"].runtimeClasspath mainClass.set("com.myktorbackend.BuildConfigGenerator") // 传递环境参数给生成器 args = listOf( env, envPropsMap[env]?.getProperty("baseUrl") ?: "", envPropsMap[env]?.getProperty("API_KEY") ?: "", envPropsMap[env]?.getProperty("GCP_API_KEY") ?: "" ) } // 让编译任务依赖对应环境的配置生成任务 tasks.named("compileKotlin") { dependsOn(taskName) } } application { mainClass.set("com.myktor-backended.ApplicationKt") // 根据传入的环境参数设置系统属性 val targetEnv = project.findProperty("env") ?: "prod" applicationDefaultJvmArgs = listOf( "-Dio.ktor.development=${targetEnv == "dev"}", "-Dapp.env=$targetEnv" ) } repositories { mavenCentral() } dependencies { // 保留原有依赖,示例如下 implementation("io.ktor:ktor-server-core-jvm:$ktorVersion") implementation("io.ktor:ktor-server-content-negotiation-jvm:$ktorVersion") implementation("io.ktor:ktor-serialization-kotlinx-json-jvm:$ktorVersion") implementation("io.ktor:ktor-server-netty-jvm:$ktorVersion") implementation("ch.qos.logback:logback-classic:$logbackVersion") testImplementation("io.ktor:ktor-server-tests-jvm:$ktorVersion") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5:$kotlinVersion") testRuntimeOnly("org.junit.platform:junit-platform-launcher") // 其他依赖... } tasks.test { useJUnitPlatform() }
3. 编写BuildConfig生成器
在src/main/kotlin/com/myktorbackend目录下创建BuildConfigGenerator.kt,用于生成对应环境的配置类:
import java.io.File fun main(args: Array<String>) { val env = args[0] val baseUrl = args[1] val apiKey = args[2] val gcpApiKey = args[3] val packageName = "com.myktorbackend" val outputPath = "src/main/kotlin/${packageName.replace(".", "/")}" val className = "BuildConfig${env.replaceFirstChar(Char::uppercase)}" val outputFile = File("$outputPath/$className.kt") // 创建输出目录(如果不存在) outputFile.parentFile.mkdirs() // 生成配置类代码 val classContent = """ package $packageName object $className { const val BASE_URL = "$baseUrl" const val API_KEY = "$apiKey" const val GCP_API_KEY = "$gcpApiKey" const val ENVIRONMENT = "$env" } """.trimIndent() // 写入文件 outputFile.writeText(classContent) }
4. 实现动态配置加载
创建统一的配置入口类AppConfig.kt,根据当前环境自动加载对应配置:
package com.myktorbackend object AppConfig { val baseUrl: String val apiKey: String val gcpApiKey: String val environment: String init { val currentEnv = System.getProperty("app.env") ?: "prod" when (currentEnv) { "dev" -> { baseUrl = BuildConfigDev.BASE_URL apiKey = BuildConfigDev.API_KEY gcpApiKey = BuildConfigDev.GCP_API_KEY environment = BuildConfigDev.ENVIRONMENT } "sit" -> { baseUrl = BuildConfigSit.BASE_URL apiKey = BuildConfigSit.API_KEY gcpApiKey = BuildConfigSit.GCP_API_KEY environment = BuildConfigSit.ENVIRONMENT } else -> { baseUrl = BuildConfigProd.BASE_URL apiKey = BuildConfigProd.API_KEY gcpApiKey = BuildConfigProd.GCP_API_KEY environment = BuildConfigProd.ENVIRONMENT } } } }
5. 在Ktor应用中使用配置
在主函数或路由中直接调用AppConfig获取配置:
fun main() { embeddedServer(Netty, port = 8080) { install(ContentNegotiation) { json() } routing { get("/status") { call.respondText("运行环境: ${AppConfig.environment}\n接口地址: ${AppConfig.baseUrl}") } } }.start(wait = true) }
6. 运行不同环境的变体
IntelliJ运行配置
修改应用运行配置的VM选项,添加环境参数:
- Dev环境:
-Dapp.env=dev - Sit环境:
-Dapp.env=sit - Prod环境:默认或添加
-Dapp.env=prod
Gradle命令行运行
# 运行开发环境 ./gradlew run -Penv=dev # 运行测试环境 ./gradlew run -Penv=sit # 运行生产环境 ./gradlew run -Penv=prod
注意事项
- 务必将
secrets.*.properties添加到.gitignore,防止敏感信息泄露到版本库 - 如果属性文件不存在,生成器会使用空字符串作为默认值,可根据需求修改默认逻辑
- 配置类会在编译前自动生成,无需手动维护
内容的提问来源于stack exchange,提问作者Klem Lloyd Mwenya
相关产品推荐
相关产品推荐

