kotlin-multiplatform

Why is Res file not generated in KMP?


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)

Solution

  • 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.