KC Blog

【Compose Multiplatform】Using Dependency Injection with Koin

2 min read
CrossPlatform#CMP#Dependency Injection#Koin#Kotlin

Introduction

In Compose Multiplatform projects

dependency injection is an important design pattern

Koin, as a lightweight DI framework

is very suitable for cross-platform development

This article will introduce how to use Koin

for dependency injection in Compose Multiplatform

{% include table/compose-multiplatform-category.html %}

Implementation Steps

1. Import Libraries
Add to your .toml file:
[versions]
koin = "3.5.0"
koinCompose = "1.2.0-Beta4"
[libraries]
koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koinCompose" }
koin-compose-viewmodel= { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koinCompose" }
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }

Add to your build.gradle.kts:

commonMain.dependencies {
implementation(libs.koin.core)
implementation(libs.koin.compose)
implementation(libs.koin.compose.viewmodel)
}
2. Implement DI Content
Next, we need to implement the specific DI content:

You can implement this based on your actual needs

For example, we might plan to use viewmodel, database, datastore, etc.

You can categorize according to your actual needs

to make your code more maintainable and manageable

expect val platformModule: Module
fun appModule() = listOf(databaseModule, platformModule, dataStoreModule, viewmodelModule)
private val viewmodelModule = module {
viewModelOf(::MainViewModel)
single { LearningViewModel(get(),get()) }
}
private val dataStoreModule = module {
single { SettingDataStore(get()) }
}
private val databaseModule = module {
single { LearningDataStore(get()) }
}
view raw CommonModule.kt hosted with ❤ by GitHub
3. Initialize Koin
If your implementation happens to need `cross-platform` access

for example, accessing Context in Android

then dependency injection needs to be injected separately

Based on different platforms and requirements, we have multiple ways to initialize Koin:

in iOSMain:

fun MainViewController() = ComposeUIViewController {
startKoin {
modules(appModule())
}
App()
}

in androidMain:

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val androidModule = module {
single<Context> { this@MainActivity.applicationContext }
}
startKoin {
modules(appModule() + androidModule)
}
setContent {
App()
}
}
}
view raw MainActivity.kt hosted with ❤ by GitHub

If your implementation happens to not need cross-platform access

you can use the following method to inject directly in commonMain

For koin-compose version 1.2.0, you can use KoinApplication

to make your code more cohesive

@Composable
fun App() {
KoinApplication(application = {
modules(appModule())
}) {
MainContent()
}
}
view raw App.kt hosted with ❤ by GitHub

Or you can also use the original startKoin:

@Composable
fun App() {
startKoin {
modules(appModule())
}
MainContent()
}
view raw App.kt hosted with ❤ by GitHub
4. Practical Use

After that, you can directly use koinViewModel to inject viewmodels

@OptIn(KoinExperimentalAPI::class)
fun NavGraphBuilder.routeLearningScreen(
navController: NavHostController,
) {
composable(ElegantJapaneseScreen.Learning.name) {
val viewModel: LearningViewModel = koinViewModel()
LearningScreen(navController, viewModel)
}
}
view raw Inject.kt hosted with ❤ by GitHub

Or for some components, you can use get() in the module to help you get instances

Conclusion

  • Koin can be used in Compose Multiplatform
  • With appropriate configuration, Koin can be used flexibly on different platforms
  • Using Koin greatly simplifies dependency management in cross-platform projects
  • Choose the appropriate initialization method based on project scale and complexity