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?
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
}
}