Heads up: Our Ideas Factory has been refreshed, levelled up, and grown-up into Alphero Intelligence. Some of our old posts are pretty cool tho'. Check this one out.

- Kotlin Multiplatform attempts to tackle the challenge faced by most cross-platform development tools in creating clean separation of platform specific code.
- We explored the concepts of the expected constructs (expect) and actual implementations (actual) with the platform specific code and shared common modules.
- Warning: Things gets a bit technical - but check out how easy Kotlin Multiplatform makes it to maintain clean separation of code across the two mobile platforms, with the Kotlin compiler doing the hard work.
Kotlin provides a language mechanism called expected/actual to access platform-specific APIs while developing common logic. This structure makes multiplatform development easier and cleaner. It can be applied to functions, properties, objects, and classes (for classes, it is stable but still in beta).
With expected and actual declarations, we can successfully separate the platform-specific implementations from the application-shared code. This allows seamless integrations between the shared and platform modules in the KMP project.
The concept
expected — It is a declaration specifying a common functionality or API that should be implemented on all target platforms but does not provide an implementation. It signals to the compiler that the platform-specific module will provide the actual implementation. The compiler will try to match each actual declaration it finds with a corresponding expected declaration. In a KMP project, the common code will be declared in the shared module commonMain.
actual — It will have the same constructor and package structure as the expected declaration, but it is located in each platform module of the project, like androidMain or iosMain. It contains an implementation that conforms to the expected declaration.
This mechanism can be applied when we need to open browsers, cameras, and platform-specific APIs.
By applying the expected/actual mechanism, the developer can abstract away platform-specific code and keep the shared codebase platform agnostic.
Before we start, dependency injection!
In this example, we are focused on creating a loosely coupled architecture; one way to achieve this is by using a dependency injection framework like Koin. If you don't know what Koin is about, check this: https://medium.com/swlh/dependency-injection-with-koin-for-android-43dda4d800d1
- In the libs.versions.toml of your Kotlin Multiplatform project, add the following Koin dependencies


We also have to add the Android dependency to build.gradle.kts file located in the android module.

For iOS, we will use a koin-core to inject the dependencies.
All good - but before we implement the actual function of openWebPage for each platform, we should create a Koin structure that will help us to provide the correct dependencies for each platform when needed.
To do so, create a class named KoinManager in commonsMain

To inject the dependencies for iOS, go to iosMain module and create a new file named ComposeView, add a new function named MainController and call KoinManager.startKoin() method.

For Android we need to start Koin a bit differently since most of the time Android requires Context as a dependency to initialise and access platform-specific APIs. Because of that, we will create an Application class in androidMain and initialise Koin passing the androidContext(). Don't forget to add it to your AndroidManifest.

Now, let's do it! Example: Open web URL
This simple example shows how straightforward it is to implement a platform-specific solution using the expected/actual mechanism.
Assume that you are developing a Store app using Kotlin Multiplatform. One of the requirements is that when the user clicks on a button, the default browser app should be started and request a webpage.
In commonMain module, let's add the following structure defining an interface called WebPageRouter and a factory function named openWebPage() that is marked with the keyword expected. This notifies the compiler that there must be actual implementations of openWebPage() in the platform modules.


We need to implement the actual WebPageRouter for each platform.
For iOS, create a file named WebPageRouter.iOS.kt in iosMain using the same package structure defined in the WebPageRouter file located in commonMain module.
Now, we can provide the value of the implemented WebPageRouter interface by defining the actual implementation for the iOS platform, in this case, the IOSWebPageRouter is the actual implementation for openWebPage().

By doing so, what will happen is that while generating the code for a specific platform, the Kotlin compiler will merge the expected and actual declarations, and it will result in only one openWebPage() function with its actual implementation.
For Android we should do the same: create a file named WebPageRouter.android.kt. The main difference here is that we will need to use the previously declared KoinManager to provide the Context dependency to create the solution.

Nice, now we have implemented the feature to open the web page from a browser for each platform.
Now in the shared module all you need to do is call openWebPage() and it will execute the actual implementation for the target platform.

The result
Github : https://github.com/lluzalves/kmpapp/tree/main
iOS
Android