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

Compose Multiplatform项目中Room数据库的Koin NoDefinitionFoundException问题

Compose Multiplatform + Koin + Room 依赖注入异常排查

问题背景

我正在开发一个Compose Multiplatform项目,采用Koin做依赖注入、Voyager实现导航、Room管理本地数据库。在尝试通过RoomDatabase.Builder提供ForgoDatabase实例时,触发了NoDefinitionFoundException。这是我第一次接触Compose Multiplatform,已经参考过各库官方文档和GitHub上的实现案例,但始终找不到问题根源。

Koin插件警告

Koin插件警告

项目配置文件

build.gradle.kts

import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
    alias(libs.plugins.kotlinMultiplatform)
    alias(libs.plugins.androidApplication)
    alias(libs.plugins.composeMultiplatform)
    alias(libs.plugins.composeCompiler)
    alias(libs.plugins.ksp.plugin)
    alias(libs.plugins.room.gradle.plugin)
}

kotlin {
    androidTarget {
        compilerOptions {
            jvmTarget.set(JvmTarget.JVM_11)
        }
    }
    
    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach { iosTarget ->
        iosTarget.binaries.framework {
            baseName = "ComposeApp"
            isStatic = true
            linkerOpts.add("-lsqlite3")
        }
    }

    room {
        schemaDirectory("$projectDir/schemas")
    }
    
    sourceSets {

        commonTest.dependencies {
            implementation(libs.kotlin.test)
        }
        
        androidMain.dependencies {
            implementation(compose.preview)
            implementation(libs.androidx.activity.compose)
            implementation(libs.koin.android)
            implementation(libs.koin.androidx.compose)
        }
        commonMain.dependencies {
            implementation(compose.runtime)
            implementation(compose.foundation)
            implementation(compose.material3)
            implementation(compose.ui)
            implementation(compose.components.resources)
            implementation(compose.components.uiToolingPreview)
            implementation(libs.androidx.lifecycle.viewmodel)
            implementation(libs.androidx.lifecycle.runtime.compose)
            implementation(libs.kotlinx.date.time)
            implementation(libs.kotlinx.coroutines)
            // Voyager
            implementation(libs.bundles.voyager)
            // Koin
            implementation(libs.koin.compose)
            implementation(libs.koin.viewmodel)
            api(libs.koin.core)
            // Room
            implementation(libs.room.runtime)
            implementation(libs.sqlite)
        }

        all {
            languageSettings.optIn("kotlin.ExperimentalMultiplatform")
            languageSettings.optIn("kotlin.RequiresOptIn")
        }
    }
    compilerOptions {
        freeCompilerArgs.add("-Xexpect-actual-classes")
    }
}

android {
    namespace = "com.feeltheboard.forgo"
    compileSdk = libs.versions.android.compileSdk.get().toInt()

    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    sourceSets["main"].res.srcDirs("src/androidMain/res")
    sourceSets["main"].resources.srcDirs("src/commonMain/composeResources")

    defaultConfig {
        applicationId = "com.feeltheboard.forgo"
        minSdk = libs.versions.android.minSdk.get().toInt()
        targetSdk = libs.versions.android.targetSdk.get().toInt()
        versionCode = 2
        versionName = "1.0.2"
    }
    packaging {
        resources {
            excludes += "/META-INF/{AL2.0,LGPL2.1}"
        }
    }
    buildTypes {
        getByName("release") {
            isMinifyEnabled = false
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
}

dependencies {
    debugImplementation(compose.uiTooling)
    add("kspCommonMainMetadata", libs.room.ksp)
    add("kspAndroid", libs.room.ksp)
    add("kspIosSimulatorArm64", libs.room.ksp)
    add("kspIosX64", libs.room.ksp)
    add("kspIosArm64", libs.room.ksp)
}

依赖版本(libs.versions.toml)

[versions]
agp = "8.9.0"
android-compileSdk = "35"
android-minSdk = "24"
android-targetSdk = "35"
androidx-activityCompose = "1.10.1"
androidx-appcompat = "1.7.0"
androidx-constraintlayout = "2.2.1"
androidx-core-ktx = "1.15.0"
androidx-espresso-core = "3.6.1"
androidx-lifecycle = "2.8.4"
androidx-material = "1.12.0"
androidx-test-junit = "1.2.1"
compose-multiplatform = "1.7.0"
kotlinx-coroutines="1.8.1"
kotlinx-date-time="0.6.2"
junit = "4.13.2"
koin = "4.0.2"
kotlin = "2.1.0"
ksp = "2.1.0-1.0.29"
room = "2.7.0-rc02"
sqlite = "2.5.0-alpha01"
voyager = "1.1.0-beta02"

核心代码实现

CommonMain 中的 SharedModule

expect val platformModule: Module

val sharedModule = module {

    single { getRoomDatabase(get()) }
    single<ForgoRepository> { ForgoRepositoryImpl(get()) }
    factory { HomeViewModel(get()) }
    factory { TaskViewModel(get()) }
}

fun appModules() = listOf(sharedModule, platformModule)

CommonMain 中的 Room 数据库定义

@Database(entities = [Task::class], version = 5, exportSchema = true)
@ConstructedBy(ForgoDatabaseConstructor::class)
abstract class ForgoDatabase : RoomDatabase() {
    abstract fun taskDao(): TaskDao
}

@Suppress("NO_ACTUAL_FOR_EXPECT")
expect object ForgoDatabaseConstructor : RoomDatabaseConstructor<ForgoDatabase> {
    override fun initialize(): ForgoDatabase
}

fun getRoomDatabase(
    builder: RoomDatabase.Builder<ForgoDatabase>
): ForgoDatabase {
    return builder
        .fallbackToDestructiveMigrationOnDowngrade(dropAllTables = true)
        .setDriver(BundledSQLiteDriver())
        .setQueryCoroutineContext(Dispatchers.IO)
        .build()
}

Android 端实现(androidMain)

fun getDatabaseBuilder(
    ctx: Context
): RoomDatabase.Builder<ForgoDatabase> {

    val appContext = ctx.applicationContext
    val dbFile = appContext.getDatabasePath("task.db")

    return Room.databaseBuilder<ForgoDatabase>(
        context = appContext,
        name = dbFile.absolutePath
    )
}

actual val platformModule: Module = module {
    single { getDatabaseBuilder(ctx = get()) }
}

class MainApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        initializeKoin {
            androidContext(this@MainApplication)
        }
    }
}

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            App()
        }
    }
}

内容的提问来源于stack exchange,提问作者Rafael Moreira

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 19:37:32