The options for adding dependency injection to a Kotlin Multiplatform project have up to now been pretty limited and if, like me, you’ve been using Koin for your Android projects then you’ll have been excited to see following announcement earlier today!



I’ve made the necessary updates to the PeopleInSpace project to start using this version in the common kotlin code module and am going to outline below the steps that were required.

I should mention at this point that Touchlab, who were actually co-developers of this capability in the library, are also using it in their KaMPKit project so would definitely recommend looking at that as well.

PeopleInSpace is by definition very minimal so the number of dependencies we need to wire up is pretty small. The Android app module had already been using Koin and had previously wired up a dependency from PeopleInSpaceViewModel to PeopleInSpaceRepository. PeopleInSpaceRepository is being used directly by the Kotlin/Native clients we have (iOS, watchOS, macOS) and, up to now, had directly instantiated PeopleInSpaceApi but with these changes we can now add that as an injected dependency.

So, first thing needed was to add following to commonMain dependencies section in build.gradle.kts in the common module.

implementation("org.koin:koin-core:3.0.0-alpha-2")

Next, we added Koin.kt containing following to common code.

fun initKoin(appDeclaration: KoinAppDeclaration = {}) = startKoin {
    appDeclaration()
    modules(commonModule)
}

// called by iOS etc
fun initKoin() = initKoin{}

val commonModule = module {
    single { PeopleInSpaceRepository() }
    single { PeopleInSpaceApi() }
}

Our Android application class (PeopleInSpaceApplication) now calls initKoin and passes in android specific application module (now only containing viewModel { PeopleInSpaceViewModel(get()) }) which is combined with commonModule (containing entries for classes that are in the common code). Now we can update PeopleInSpaceRepository to firstly implement KoinComponent and to start using PeopleInSpaceApi as an injected dependency

class PeopleInSpaceRepository() : KoinComponent {
    private val peopleInSpaceApi: PeopleInSpaceApi by inject()
    ...
}

The next key step is to start calling KoinKt.doInitKoin() (which corresponds to initKoin method in Koin.kt) at application startup in the iOS, watchOS and macOS clients. The following for example was added to iOS client. With that change we can use PeopleInSpaceRepository in for example our iOS code and any dependencies needed (PeopleInSpaceApi) will have been injected.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    KoinKt.doInitKoin()
    return true
}

And that’s it! This is the commit to PeopleInSpace repo containing these changes.

One last note - the KaMPKit project mentioned earlier also has nice example of using expect/actual to provide per platform module definitions that can be pulled in and included as well (used for example for settings and for providing platform dependent version of SqlDriver)

Featured in Kotlin Weekly Issue #198

(purpose of providing this is primarily to help “close the loop” and provide way to post feedback/ask questions etc (in absence for now of that functionality in blog itself).