kotlinandroid-jetpack-composekotlin-multiplatformkoinsqldelight

Injecting Context from Android into SqlDelight Driver using koin within KMP


I have a Kotlin Multi-platform project, that has iOS, Android and Desktop in it, and I wanted to use SqlDelight to store data. however I'm using Koin as a DI.

Since I have several platforms, I made the commonMain to startKoin.

This file contains the expect value that will return the SqlDriver for each platform, and rest of the needed implementation to communicate with the database from commonMain.

expect val dbModule: Module

val repoModel = module {
    single<DbRepository> {
        DbRepository(get<SqlDriver>())
    }
}

fun initKoin() = startKoin {
    modules(
        dbModule,
        repoModel
    )
}

I found out that each platform have an Issue, so I decided to focus on one platform at a time.

the problem of the Android platform is that you can't get the context needed for the AndroidSqliteDriver.

actual val dbModule: Module = module {
    single<SqlDriver> {
        AndroidSqliteDriver(Kos.Schema, androidContext(), "Kos")
    }
}

for Android, you need the context to initialize the driver, but you have no way to inject it. since I'm starting Koin from commonMain, I couldn't find a way to get the android context from the Application class. I tried this way:

class MyApp: Application() {
    override fun onCreate() {
        super.onCreate()
        startKoin {
            androidContext(this@MyApp)
        }
    }
}

also this way

class MyApp: Application() {
    override fun onCreate() {
        super.onCreate()
        koinApplication {
            androidContext(this@MyApp)
        }
    }
}

and even this way

class MyApp: Application() {
    override fun onCreate() {
        super.onCreate()
        loadKoinModules(
            module { 
                single { this@MyApp }
            }
        )
    }
}

and I always get an error...

Caused by: org.koin.core.error.KoinAppAlreadyStartedException: A Koin Application has already been started

Caused by: org.koin.android.error.MissingAndroidContextException: Can't resolve Context instance. Please use androidContext() function in your KoinApplication configuration.

how is it possible to get android context for SqlDelight driver withing kmp using Koin?


Solution

  • I tried several ways... the only way it worked for me is to get the context manually into Koin.

    @SuppressLint("StaticFieldLeak")
    lateinit var androidContext: Context
    
    actual val dbModule: Module = module {
        single<Context> { androidContext }
        single<SqlDriver> {
            AndroidSqliteDriver(ReminderDb.Schema, get(), "ReminderDb")
        }
    }
    
    class MyApp: Application() {
        override fun onCreate() {
            super.onCreate()
            androidContext = applicationContext
        }
    }