【Compose Multiplatform】Using Dependency Injection with Koin
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
Implementation Steps
[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) | |
} |
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()) } | |
} |
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() | |
} | |
} | |
} |
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() | |
} | |
} |
Or you can also use the original startKoin
:
@Composable | |
fun App() { | |
startKoin { | |
modules(appModule()) | |
} | |
MainContent() | |
} |
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) | |
} | |
} |
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