Koin is a pragmatic lightweight dependency injection framework for Kotlin & Kotlin Multiplatform.

Koin step by step Link to heading

💡Source Code

💡For Compose Multiplatform Project

💡Use MVVM Pattern

Add dependency Link to heading

Koin/gradle/libs.versions.toml

[versions]
...
koin = "4.0.2"

[libraries]
...
koin-compose-viewmodel = {module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koin"}
koin-android = {module = "io.insert-koin:koin-android", version.ref = "koin"}

Koin/composeApp/build.gradle.kts

sourceSets {
    androidMain.dependencies {
        ...
        implementation(libs.koin.android)
    }
    commonMain.dependencies {
        ...
        implementation(libs.koin.compose.viewmodel)
    }
}

Create Model Link to heading

Koin/composeApp/src/commonMain/kotlin/tokyo/randx/portfolio/kmp/data/Transaction.kt

data class Transaction(
    val transactionId: String,
    val amount: Int
)

val dummyTransactions = listOf(
    Transaction("1", 5000),
    Transaction("2", 1000),
    Transaction("3", 10000)
)

Create Repository Link to heading

Koin/composeApp/src/commonMain/kotlin/tokyo/randx/portfolio/kmp/data/TransactionRepository.kt

interface TransactionRepository {
    fun findTransaction(transactionId: String): Transaction?
    fun addTransaction(transactions: List<Transaction>)
}

class TransactionRepositoryImpl : TransactionRepository {
    private val _transactions = arrayListOf<Transaction>()

    init {
        addTransaction(dummyTransactions)
    }

    override fun findTransaction(transactionId: String): Transaction? {
        return _transactions.firstOrNull { it.transactionId == transactionId }
    }

    override fun addTransaction(transactions: List<Transaction>) {
        _transactions.addAll(transactions)
    }
}

Create ViewModel Link to heading

Koin/composeApp/src/commonMain/kotlin/tokyo/randx/portfolio/kmp/viewmodel/TransactionViewModel.kt

import androidx.lifecycle.ViewModel
import tokyo.randx.portfolio.kmp.Platform
import tokyo.randx.portfolio.kmp.data.TransactionRepository

class TransactionViewModel(
    private val repository: TransactionRepository,
    private val platform: Platform
) : ViewModel() {
    fun showTransaction(transactionId: String): String {
        val transaction = repository.findTransaction(transactionId)
        return transaction?.let { "ID is $transactionId Amount is ${it.amount} " } ?: "Transaction $transactionId not found!"
    }

    fun getPlatform() = platform.name
}

Create AppModule Link to heading

Koin/composeApp/src/commonMain/kotlin/tokyo/randx/portfolio/kmp/di/AppModule.kt

val appModule = module {
    singleOf(::TransactionRepositoryImpl) { bind<TransactionRepository>() }
    viewModelOf(::TransactionViewModel)
    factory { getPlatform(this) }
}

Create KoinApp Link to heading

Koin/composeApp/src/commonMain/kotlin/tokyo/randx/portfolio/kmp/di/KoinApp.kt

import org.koin.core.context.startKoin
import org.koin.dsl.KoinAppDeclaration
import org.koin.dsl.includes

fun initKoin(configuration: KoinAppDeclaration? = null) {
    startKoin {
        printLogger()
        includes(configuration)
        modules(appModule)
    }
}

Init Koin Link to heading

Koin/composeApp/src/androidMain/kotlin/tokyo/randx/portfolio/kmp/KoinApplication.kt

import android.app.Application
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import tokyo.randx.portfolio.kmp.di.initKoin

class KoinApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        initKoin {
            androidContext(this@KoinApplication)
            androidLogger()
        }
    }
}

Koin/composeApp/src/androidMain/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <application
        android:name=".KoinApplication"
        ...
        android:theme="@android:style/Theme.Material.Light.NoActionBar">
        ...
    </application>

</manifest>

Koin/composeApp/src/iosMain/kotlin/tokyo/randx/portfolio/kmp/MainViewController.kt

...
import tokyo.randx.portfolio.kmp.di.initKoin

fun MainViewController() = ComposeUIViewController(
    configure = {
        initKoin()
    }
) {
    App()
}

Inject Dependancy Link to heading

Koin/composeApp/src/commonMain/kotlin/tokyo/randx/portfolio/kmp/App.kt

...
import org.koin.compose.KoinContext
import org.koin.compose.viewmodel.koinViewModel
import tokyo.randx.portfolio.kmp.viewmodel.TransactionViewModel

@Composable
@Preview
fun App() {
    MaterialTheme {
        KoinContext {
            val viewModel = koinViewModel<TransactionViewModel>()
            ...
        }
    }
}

Reference Link to heading