You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin Multiplatform(KMP)项目中Res文件未生成问题求助

KMP Compose 公共资源访问问题: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 03:25:56