DEV Community

Cover image for KMP Native UI Dependency Injection with Koin
Saad Alkentar
Saad Alkentar

Posted on

KMP Native UI Dependency Injection with Koin

Cross-platform development significantly reduces overhead for both developers and organizations. While React Native leveraged web expertise and Flutter introduced a unified UI for multi-platform delivery, Kotlin Multiplatform (KMP) represents the next evolution. KMP offers the flexibility of Compose for shared UI, while uniquely allowing developers to implement native interfaces where maximum performance and stability are required—all while maintaining a single shared logic base in Kotlin.

Finding comprehensive resources for Kotlin Multiplatform (KMP) using Native UI can be challenging, so this series aims to bridge that gap.

We will build a production-ready foundation using a modular Clean Architecture—the industry standard for scalable apps. Our roadmap covers the essential pillars of modern development:

  • Dependency Injection,
  • Networking,
  • and Architecture.

In this first installment, we’ll kick things off by implementing Dependency Injection with Koin.

Creating a new Project

The recommended IDEs are IntelliJ IDEA and Android Studio. I'll use Android Studio

  1. Install the KMP plugin: in the sidebar of Android Studio, select plugins
    Android Studio Plugins

  2. Look for "Kotlin Multiplatform" and install it

  3. It is time to create a new Project
    KMP project

  4. Complete the wizard process by choosing the project name, and do not share the UI

Select Project Name

Do not use shared UI

That is it, simple and easy

Koin Implementation Guide for Native UI

We start with:

Koin Build libs

Basically, it is this article from Koin documentation, in short:

  • in gradle/libs.versions.toml:
[versions]
koin = "4.2.0"
koin-plugin = "0.4.1"

[libraries]
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
koin-annotations = { module = "io.insert-koin:koin-annotations", version.ref = "koin" }
koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koin" }
koin-compose-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koin" }
koin-ktor = { module = "io.insert-koin:koin-ktor", version.ref = "koin" }
koin-test = { module = "io.insert-koin:koin-test", version.ref = "koin" }

[plugins]
koin-compiler = { id = "io.insert-koin.compiler.plugin", version.ref = "koin-plugin" }
Enter fullscreen mode Exit fullscreen mode
  • In the shared module's shared/build.gradle.kts:
plugins {
    alias(libs.plugins.koin.compiler)
}

kotlin {
    ...

    sourceSets {
        commonMain.dependencies {
            implementation(libs.koin.core)
            implementation(libs.koin.annotations)
            implementation(libs.koin.compose.viewmodel)
            implementation(libs.koin.ktor) // for Ktor web client DI
        }


        commonTest.dependencies {
            implementation(libs.koin.test)
        }
    }

}

Enter fullscreen mode Exit fullscreen mode
  • In the Android module's composeApp/build.gradle.kts
kotlin {
    ...

    sourceSets {
        ...
        commonMain.dependencies {
            ...
            implementation(libs.koin.compose) // contains android

        }
        ...
    }
}

Enter fullscreen mode Exit fullscreen mode

Compose contains the Android Koin dependency; it can be used as a common or Android dependency.

Koin Project setup

After installing all libraries, it is time to set up the code. You can follow this also to set it up

  • create KoinModules in the shared module
// shared/commonMain/kotlin/di/KoinModules.kt
import org.koin.core.module.Module
import org.koin.dsl.module

val sharedModule = module {

}

expect val platformModule: Module
Enter fullscreen mode Exit fullscreen mode
  • create the platform modules, Android
// shared/androidMain/kotlin/di/PlatformModule.android.kt
import org.koin.dsl.module

actual val platformModule = module {

}
Enter fullscreen mode Exit fullscreen mode

iOS:

// shared/iosMain/kotlin/di/PlatformModule.ios.kt
import org.koin.dsl.module

actual val platformModule = module {

}
Enter fullscreen mode Exit fullscreen mode
  • Koin initialization: we start with the shared module
// shared/commonMain/kotlin/di/KoinInit.kt
import org.koin.core.context.startKoin
import org.koin.core.KoinApplication
import org.koin.dsl.KoinAppDeclaration
import org.koin.dsl.includes

fun initKoin(config: KoinAppDeclaration? = null): KoinApplication {
    return startKoin {
        includes(config)
        modules(
            sharedModule,
            platformModule
        )
    }
}
Enter fullscreen mode Exit fullscreen mode

Now, with the Android module, the simplest way is to add initKoin() in the MainActivity

// composeApp/kotlin/MainActivity.kt
...
import com.irsc.kotlinnativedemo.di.initKoin

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        initKoin()
        ...
    }
}
Enter fullscreen mode Exit fullscreen mode

But for the iOS module, we will follow the instructions this time. Let's start by creating KoinInitIos in the shared module.

// shared/src/iosMain/kotlin/di/KoinInitIos.kt
fun initKoinIos() {
    initKoin()
}
Enter fullscreen mode Exit fullscreen mode

Now to call it in the iOS native code

import SwiftUI
import Shared

@main
struct iOSApp: App {

    init() {
        KoinInitIosKt.doInitKoinIos()
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Please notice that we are importing Shared (capital S), the Kotlin file KoinInitIos.kt is used with Kt postfix, and the function is used with do prefix

I have submitted a fix for the documentation code; hopefully, it will be fixed by the time you read this article

That is it, we have added Koin to our project successfully. The next step is to test it with view model injection

Stay tuned for the next article

Top comments (0)