I'm new to Kotlin Multiplatform (KMP) and recently started working on a sample project.
I created the project using Jetbrains, then opened it in Android Studio to adjust some dependencies and resources. Everything seems to be working fine, and the app runs on both Android and iOS. However, I'm running into an issue with drawable
/string
resources.
Specifically, when trying to access a drawable (e.g. Res.drawable.ic_menu
) located in commonMain/composeResources/drawable
, the Res
is unresolved. It seems like the corresponding Res
file isn't being generated during the build process.
After some research and asking ChatGPT, I found suggestions stating that the composeResources
directory should not be used, and instead, I should use commonMain/resources/drawable
. However, even after trying that, the Res
file is still not generated.
Here is my gradle setup:
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)
}
and here the libs:
[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" }
Does anyone know what might be causing this issue?
Also, please let me know if there’s any additional code or project configuration I should share to help clarify the problem. Thanks in advance!
Solution:
Just needed to used the default dependency for resources lib:
implementation(compose.components.resources)
Are you following the docs to add it? It seems like you want the composeResources
directory. If you're using the wizard then that directory already comes with a drawable, so I'm not sure where the issue comes from.
Maybe try `
implementation(compose.components.resources)
The compose compiler plugin comes with existing dependency definitions.
Also you shouldn't need an empty resources
block.
I would recommend pulling down a new project from the wizard and seeing what differences you have between that project and your current project.