In this article, we will walk through the steps required to integrate ViewModel with Koin in a Kotlin Multiplatform project. Koin is a popular dependency injection library that helps in managing object lifecycles, and Jetpack Compose provides a powerful, declarative way to build UIs in Android and across other platforms. By combining these two technologies, we can effectively manage state in a cross-platform application (Android, iOS and desktop platforms).
Step 1: Add Dependencies to libs.versions.toml
First, add the necessary dependencies for Koin and Lifecycle ViewModel in your libs.versions.toml file. This file defines the versions and library modules you'll use in your project:
[versions]
# Define the versions of the dependencies
koin = "4.0.0"
lifecycleViewmodel = "2.8.2"
[libraries]
# Koin dependencies
koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" }
koin-androidx-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin" }
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koin" }
koin-composeVM = { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koin" }
# Lifecycle ViewModel
androidx-lifecycle-viewmodel = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel", version.ref = "lifecycleViewmodel" }
Next, include these dependencies in the build.gradle.kts file of your Compose Multiplatform project to make them available across platforms:
// build.gradle.kts (Module :composeApp)
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
// Koin
api(libs.koin.core)
implementation(libs.koin.compose)
implementation(libs.koin.composeVM)
// ViewModel support in common code
implementation(libs.androidx.lifecycle.viewmodel)
}
}
val androidMain by getting {
dependencies {
// Koin support for Android
implementation(libs.koin.android)
implementation(libs.koin.androidx.compose)
}
}
// Additional source sets for iOS, Desktop as needed
}
}
Step 2: Create the ViewModel with StateFlow
After syncing your Gradle files, create a CounterViewModel.kt file that uses StateFlow to manage a counter variable. This will provide a shared counter logic for all platforms:
// composeApp/src/commonMain/kotlin/CounterViewModel.kt
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import androidx.lifecycle.ViewModel
class CounterViewModel : ViewModel() {
// Define the counter variable using StateFlow
private val _counter = MutableStateFlow(0)
val counter: StateFlow<Int> = _counter
// Increment method
fun increment() {
_counter.value += 1
}
// Decrement method
fun decrement() {
_counter.value -= 1
}
}
Step 3: Define and Implement ViewModel Modules
In commonMain, define the ViewModelModule using viewModelOf for a cleaner and more concise way to declare the ViewModel:
// composeApp/src/commonMain/kotlin/ViewModelModule.kt
import org.koin.core.module.dsl.viewModel
import org.koin.core.module.dsl.viewModelOf
import org.koin.dsl.module
val viewModelModule = module {
// Old way
viewModel { CounterViewModel() }
// New way using viewModelOf
viewModelOf(::CounterViewModel)
}
Note: Currently, nested NavGraph or navigation with multi-stack configurations are not fully supported. The issue arises with ViewModel recreation when navigating between multiple stacks. In the future, official support for multi-back-stack navigation is expected to resolve this problem.
Step 4: Initialize Koin in Each Platform
Common Main
For dependency injection, initialize Koin on each platform. Create a Koin.kt file in the commonMain source set:
// composeApp/src/commonMain/kotlin/Koin.kt
import org.koin.core.context.startKoin
import org.koin.core.KoinApplication
import org.koin.core.module.Module
import org.koin.core.context.KoinContext
fun initKoin(appDeclaration: KoinAppDeclaration = {}) =
startKoin {
appDeclaration()
modules(
viewModelModule
)
}
Android
In the androidMain source set, create MyApp.kt:
// composeApp/src/androidMain/kotlin/your_package_name/MyApp.kt
import android.app.Application
class MyApp : Application(), KoinComponent {
override fun onCreate() {
super.onCreate()
initKoin {
androidLogger()
androidContext(this@MyApp)
}
}
}
After that, we need to add the name into our AndroidMainfest.xml:
<!-- composeApp/src/androidMain/AndroidManifest.xml -->
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Add this code android:name=".MyApp" in application-->
<application
android:name=".MyApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@android:style/Theme.Material.Light.NoActionBar">
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|mnc|colorMode|density|fontScale|fontWeightAdjustment|keyboard|layoutDirection|locale|mcc|navigation|smallestScreenSize|touchscreen|uiMode"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Desktop
In the desktopMain source set, update main.kt:
// composeApp/src/desktopMain/kotlin/main.kt
import androidx.compose.ui.window.application
fun main() = application {
initKoin()
App()
}
iOS
In the iosMain source set, configure Koin in MainViewController.kt:
// composeApp/src/iosMain/kotlin/MainViewController.kt
import androidx.compose.ui.platform.ComposeUIViewController
fun MainViewController() = ComposeUIViewController(
configure = {
initKoin()
}
) {
App()
}
Step 5: Initialize ViewModel in Compose Using Koin
To connect the ViewModel with your UI, use koinViewModelto inject the ViewModel. Update App.kt in the commonMain source set to initialize the CounterViewModel and set up the UI with a text view, increment, and decrement buttons and Finally we need to wrap our composable screens within KoinContext composable.
// composeApp/src/commonMain/kotlin/App.kt
import androidx.compose.runtime.Composable
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import org.koin.compose.KoinContext
import org.koin.compose.viewmodel.koinViewModel
@Composable
fun App() {
KoinContext {
val viewModel = koinViewModel<CounterViewModel>()
val counterValueState by viewModel.counter.collectAsState()
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(text = "Counter: $counterValueState")
Spacer(modifier = Modifier.height(16.dp))
Row {
Button(onClick = { viewModel.increment() }) {
Text(text = "Increment")
}
Spacer(modifier = Modifier.width(16.dp))
Button(onClick = { viewModel.decrement() }) {
Text(text = "Decrement")
}
}
}
}
}
Conclusion
You’ve successfully integrated ViewModel in Compose Multiplatform with Koin. Now, you can run the app on each platform — Android, iOS, macOS, Linux, and Windows — to ensure everything works smoothly.
If you’re interested in learning more about Kotlin Multiplatform and Compose Multiplatform, check out my playlist on YouTube Channel:
Kotlin Multiplatform & Compose Multiplatform
Thank you for reading! 🙌🙏✌ I hope you found this guide useful.
Don’t forget to clap 👏 to support me and follow for more insightful articles about Android Development, Kotlin, and KMP. If you need any help related to Android, Kotlin, and KMP, I’m always happy to assist.
Explore More Projects
If you’re interested in seeing full applications built with Kotlin Multiplatform and Jetpack Compose, check out these open-source projects:
- News Kotlin Multiplatform App (Supports Android, iOS, Windows, macOS, Linux):
News KMP App is a Kotlin Compose Multiplatform (KMP) project that aims to provide a consistent news reading experience across multiple platforms, including Android, iOS, Windows, macOS, and Linux. This project leverages Kotlin’s multiplatform capabilities to share code and logic while using Compose for UI, ensuring a seamless and native experience on each platform.
GitHub Repository: News-KMP-App - Gemini AI Kotlin Multiplatform App (Supports Android, iOS, Windows, macOS, Linux, and Web):
Gemini AI KMP App is a Kotlin Compose Multiplatform project designed by Gemini AI where you can retrieve information from text and images in a conversational format. Additionally, it allows storing chats group-wise using SQLDelight and KStore, and facilitates changing the Gemini API key.
GitHub Repository: Gemini-AI-KMP-App
Follow me on
Medium , YouTube , GitHub , Instagram , LinkedIn , Buy Me a Coffee , Twitter
How to Integrate ViewModel in Kotlin Multiplatform with Koin was originally published in ProAndroidDev on Medium, where people are continuing the conversation by highlighting and responding to this story.
