Blog Infos
Author
Published
Topics
Published
Topics

During the migration process of the Quotes project to KMM (Kotlin Mobile Multiplatform), I had to implement different classes for each platform, and I was using Koin for dependency injection.

One of such classes was NetworkHandler, which had a single method called hasNetworkConnection() that was checking network connectivity, and I needed to implement this class on both Android and iOS platforms. The way of doing this in multiplatform development, we declare something as expected and then provide the actual implementation for each platform( https://kotlinlang.org/docs/multiplatform-connect-to-apis.html).

I had two initial ideas for implementing this, and I’ll go through each of them.

Naive approach — NetworkHandler class as expected class:
The idea was to declare the NetworkHandler class as an expected class, and then provide the actual implementation for each platform. Something like this:

//commonMain module
expect class NetworkHandler(){
 fun hasNetworkConnection():Boolean
}

------------------------------------

//iosMain or androidMain module
actual class NetworkHandler actual constructor() {
 actual fun hasNetworkConnection():Boolean {
  //implementation specific to each module
 }
}

When I look at the NetworkHandler class implementation, I noticed that it depended on the Android application context. And in the iOS environment I didn’t even have a clue what dependencies it will need, so, this approach didn’t work. Hence, I had to consider an alternative solution.

Main approach — Creating NetworkHandler interface and providing an implementation in each platform:

//commonMain module
interface NetworkHandler {
 fun hasNetworkConnection():Boolean
}

--------------------------------------

//androidMain module
class AndroidNetworkHandler(context:Context):NetworkHandler{
 override fun hasNetworkConnection(): Boolean {
     //implementation in android world
 }
}

----------------------------------------

//iosMain module
class IosNetworkHandler():NetworkHandler{
 override fun hasNetworkConnection(): Boolean {
    // I still don't know how is implemenation in ios 
    // so I just return true here :D
    return true 
 }
}

So far so good, but there was still one issue. I was using Koin as DI, and in core module I needed to provide the actual implementation of NetworkHandler class. Before the migration to a multiplatform, it was as follows:

val coreModule = module {
 single<NetworkHandler> { NetworkHandler(androidContext()) }
}

Now in my multiplatform core module I needed to say to koin somehow “Hey btw Koin, here is my actual implementation of NetworkHandler for each platform” and this is when I discovered the powerful capability of Koin using the “include” and “constructor DSL” feature. The idea is to divide the Koin module into two parts: a common module and a platform-specific module. The platform-specific module is declared as an expected variable, and the actual implementation is provided in each platform. By using the “include” feature, we combine these modules into one single module.

OUR VIDEO RECOMMENDATION

,

Building Bridges with Kotlin Multiplatform Mobile (KMM): How we added KMM to our established App

Learn how we integrated Kotlin Multiplatform Mobile (KMM) into our Android and iOS codebase. We will share our experience, challenges, and best practices for adding KMM to existing apps.
Watch Video

Building Bridges with Kotlin Multiplatform Mobile (KMM): How we added KMM to our established App

Benedict Pregler & Kristijan Vidovic
Senior Mobile Engineer & Mobile Engineer
GetYourGuide

Building Bridges with Kotlin Multiplatform Mobile (KMM): How we added KMM to our established App

Benedict Pregler & ...
Senior Mobile Engine ...
GetYourGuide

Building Bridges with Kotlin Multiplatform Mobile (KMM): How we added KMM to our established App

Benedict Pregler ...
Senior Mobile Engineer & ...
GetYourGuide

Jobs

No results found.

//commonMain module
private val commonCoreModule = module {
 //Add common core module implementations here
}

//https://github.com/InsertKoinIO/koin/issues/1341
// writing get() is important
val coreModule : Module get() =  module {
 includes(commonCoreModule + platformCoreModule)
}

internal expect val platformCoreModule:Module

-------------------------------

//androidMain module
internal actual val platformCoreModule: Module = module {
 singleOf(::AndroidNetworkHandler) bind NetworkHandler::class
}

------------------------------------

//iosMain module
internal actual val platformCoreModule: Module = module {
 singleOf(::IosNetworkHandler) bind NetworkHandler::class
}

By following this approach, I was able to successfully provide different implementations for each platform using Koin. This allowed me to customize the behavior of the NetworkHandler class based on the specific requirements of each platform.

 

This article was previously published on proandroiddev.com

 

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
First of all, let’s explain why I need the CookiesStorage. To identify the user,…
READ MORE
blog
I thought Kotlin Multiplatform Mobile was complicated to use before I decided to try…
READ MORE
blog
Hey everyone, I want to share more of Kotlin Multiplatform Mobile Content since it…
READ MORE
blog
In my previous story, I’ve talked about why I believe we can strongly improve…
READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu