Kotlin Multiplatform(KMP)项目中Res文件未生成问题求助
问题描述
作为KMP新手,我通过JetBrains创建了示例项目,调整依赖和资源后应用可在Android、iOS正常运行,但访问公共资源时遇到问题:尝试访问commonMain/composeResources/drawable下的资源(如Res.drawable.ic_menu)时,Res标识符无法解析,构建过程未生成对应的Res文件。尝试将资源目录改为commonMain/resources/drawable后问题仍存在。
以下是项目的Gradle配置和依赖版本:
项目根目录 build.gradle.kts
import org.jetbrains.compose.desktop.application.dsl.TargetFormat import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { alias(libs.plugins.android.ksp) alias(libs.plugins.android.room) alias(libs.plugins.serialization) alias(libs.plugins.compose.compiler) alias(libs.plugins.android.application) alias(libs.plugins.kotlin.multiplatform) alias(libs.plugins.compose.multiplatform) } room { schemaDirectory("$projectDir/schemas") } kotlin { androidTarget { compilerOptions { jvmTarget.set(JvmTarget.JVM_17) } } jvm(name = "desktop") listOf( iosX64(), iosArm64(), iosSimulatorArm64() ).forEach { iosTarget -> iosTarget.binaries.framework { baseName = "ComposeApp" isStatic = true linkerOpts.add("-lsqlite3") } } sourceSets { androidMain.dependencies { // Koin implementation(libs.koin.android) // Room implementation(libs.androidx.room) implementation(libs.androidx.room.runtime) implementation(libs.androidx.activity.compose) } commonMain.dependencies { // Koin api(libs.koin.core) implementation(libs.koin.compose) // Navigation implementation(libs.navigation.compose) // SQLite implementation(libs.sqlite.bundled) // Room implementation(libs.androidx.room.runtime) // Serialization implementation(libs.kotlinx.serialization.core) implementation(libs.kotlinx.serialization.json) // Compose UI implementation(libs.compose.ui) implementation(libs.compose.ui.backhandler) // Compose dependencies implementation(libs.compose.runtime) implementation(libs.compose.material3) implementation(libs.compose.foundation) implementation(libs.animation.graphics) implementation(libs.compose.components.resources) // Lifecycle dependencies implementation(libs.androidx.lifecycle.viewmodel) implementation(libs.androidx.lifecycle.runtime.compose) implementation(libs.androidx.lifecycle.viewmodel.compose) } val desktopMain by getting desktopMain.dependencies { implementation(compose.desktop.currentOs) implementation(libs.kotlinx.coroutines.swing) } } } android { compileSdk = 35 namespace = "com.example.sampleapp" defaultConfig { applicationId = "com.example.sampleapp" minSdk = 28 targetSdk = 35 versionCode = 1 versionName = "1.0" } packaging { resources { excludes += "/META-INF/{AL2.0,LGPL2.1}" } } buildTypes { getByName("release") { isMinifyEnabled = false } } buildFeatures { compose = true buildConfig = true } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } } compose { desktop { application { mainClass = "com.example.sampleapp.MainKt" nativeDistributions { targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) packageName = "com.example.sampleapp" packageVersion = "1.0.0" } } } resources { // This block enables common resource generation for all platforms. // You can leave it empty for default configuration. } } dependencies { add("kspIosX64", libs.androidx.room.compiler) add("kspDesktop", libs.androidx.room.compiler) add("kspAndroid", libs.androidx.room.compiler) add("kspIosArm64", libs.androidx.room.compiler) add("kspIosSimulatorArm64", libs.androidx.room.compiler) }
gradle/libs.versions.toml
[versions] agp = "8.10.0" koin = "4.0.3" room = "2.7.1" kotlin = "2.1.20" runtime = "1.8.0" foundation = "1.8.0" compose-ui = "1.8.0" ksp = "2.1.20-2.0.1" sqlite-bundled = "2.5.1" compose-material3 = "1.8.0" animation-graphics = "1.8.0" androidx-lifecycle = "2.8.4" kotlinx-coroutines = "1.10.2" components-resources = "1.7.3" compose-multiplatform = "1.8.0" kotlinx-serialization = "1.8.1" navigation-compose = "2.9.0-beta01" androidx-activity-compose = "1.10.1" [libraries] #Room androidx-room = { module = "androidx.room:room-ktx", version.ref = "room" } androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" } androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" } #SQLite sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version.ref = "sqlite-bundled" } #UI compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "compose-ui" } compose-ui-backhandler = { module = "org.jetbrains.compose.ui:ui-backhandler", version.ref = "compose-ui" } compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "runtime" } compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", version.ref = "foundation" } compose-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "compose-material3" } androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity-compose" } kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" } animation-graphics = { module = "org.jetbrains.compose.animation:animation-graphics", version.ref = "animation-graphics" } compose-components-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "components-resources" } #Lifecycle androidx-lifecycle-viewmodel = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel", version.ref = "androidx-lifecycle" } androidx-lifecycle-runtime-compose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-compose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } # Navigation navigation-compose = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "navigation-compose" } # Serialization kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinx-serialization" } kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" } # Koin koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" } koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" } koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koin" } [plugins] android-room = { id = "androidx.room", version.ref = "room" } android-library = { id = "com.android.library", version.ref = "agp" } android-ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } android-application = { id = "com.android.application", version.ref = "agp" } compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } compose-multiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
可能的原因及解决方案
1. 资源目录结构不符合要求
Compose Multiplatform的公共资源必须放在commonMain/composeResources目录下,而非commonMain/resources。正确的目录结构应为:
commonMain/ └── composeResources/ ├── drawable/ │ └── ic_menu.png # 图片资源 └── values/ └── strings.xml # 字符串资源
确保所有资源都放在composeResources下,且子目录名称符合Android资源规范(如drawable、values)。
2. 依赖版本不兼容
你的components-resources版本是1.7.3,而compose-multiplatform版本是1.8.0,版本不一致会导致资源生成插件无法正常工作。在gradle/libs.versions.toml中统一版本:
components-resources = "1.8.0" # 和compose-multiplatform版本保持一致
3. 构建缓存导致的问题
旧的构建缓存可能阻止Res类生成。执行以下操作清理缓存并重新构建:
- 运行命令:
./gradlew clean build - 或在Android Studio中点击
File -> Invalidate Caches... -> Invalidate and Restart
4. 资源命名不符合规范
资源文件名必须使用小写字母和下划线,不能包含大写字母、空格或特殊字符。例如,ic_menu.png是合法的,而ICMenu.png或ic menu.png会导致生成失败。
5. 检查Gradle配置的资源块
确保compose.resources块存在于根项目的build.gradle.kts中,即使是空块也能启用资源生成。你的配置中已经包含该块,这部分没问题,但如果之前遗漏会导致无法生成Res类。
内容的提问来源于stack exchange,提问作者Mark Delphi

