Kotlin Multiplatform Mobile(KMM) : Code sharing between Android and iOS

Hardik Trivedi
Globant
Published in
10 min readDec 11, 2020
With KMM Android and iOS can be BFF
With KMM Android and iOS can be BFF

This blog will help you to understand the potential of Kotlin multiplatform mobile aka KMM when it comes to sharing a code between Android and iOS. I evaluated the KMM for our projects and now sharing here our experience with you all.

Motivation

  • The first motivation factor is you want to develop the Android and iOS Application? But don’t want to do the job twice!
  • You simply love DRY (Do not Repeat Yourself) principal! But don’t know how to start.
  • Or may be you have less expertise in iOS.
  • As a good software engineer, you also want to quickly deliver feature but with quality.
  • But do not like existing cross platform technology for some reason.

If above points motivates you enough let’s understand what actually KMM is.

What is KMM?

  • Allows you to write code once and use on multiple platforms such as Android and iOS.
  • It reduces testing effort.
  • Has a less maintenance headache, as modification comes easy and fast.
  • It’s using Kotlin and that is statically typed language and gives benefit of native programming language.
  • For Android engineers nothing really changes and for iOS project we just import a framework just like any Swift based framework.
  • If you plan appropriately development time can be reduced to 30–40% for iOS where they only have to write UI layer for it.

KMM and modern application’s architecture

Modern times requires modern applications and modern application requires modern architectures. Both Android and iOS ecosystem are in a phase where they don’t go well with stereotype architecture patterns. They demand much more. We have concepts like caching, maintaining view state, staying aware about lifecycle changes etc, and following diagram explains what layer of your application can be shared. You will get some idea that where exactly you can leverage concepts of KMM.

What can be shared in the modern architecture
What can be shared in the modern architecture

From the above diagram you can easily understand that on the data layer which has classes with the responsibility of making network calls and database queries can be 100% shared. KMM provides you this power with the help of Ktor. Ktor is a framework which enables you to make asynchronous network calls. And there is another framework called SQLDelight, from square.io which is compatible with KMM and allows you to write code to make some SQLite database operations.

How KMM works?

So you must be wondering and thinking about how this entire things works. Let me help you to understand that bit using a diagram.

How KMM works?
How KMM works? Icons by Freepik

In the above visual representation you can see how I have divided idea in three main layers, i.e. Shared code, iOS native code and Android native code.

Shared code will have common implementation of the business logic around network calls and other core utility type of functions.

KMM is flexible enough where it allows developer to differ with Android and iOS specific API implementation where ever required. It uses expect/actual mechanism to achieve this. We’ll learn about expect/actual soon in this article.

Once the shared module is built, the final outcome of the shared module is .framework file for iOS and .jar file for Android. So logically speaking both your Android and iOS projects don’t even know that shared module is written in Kotlin, for them it’s just another dependency.

KMM : Step by step guide

At this point you should have a good enough understanding how conceptually KMM works for Android and iOS. Now is the time to actually implement this entire concept in a step by step manner.

1. Tools you need

To develop any KMM project you need following four tools.

Android Studio : You need AS 4.0 and above to write your shared code and Android application.

Xcode : XCode 11.3.1 and above lets you write iOS application and it is also needed to compile and build your iOS application

KMM Plugin : KMM plugin allows you to create KMM project using wizard and comes with custom gradle task which builds iOS application.

macOS : Sine the entire iOS ecosystem is running on macOS you need macOS to write and test iOS application.

2. Setting up KMM project

Install the KMM plugin from your AndroidStudio’s Preference ->Plugins-> Marketplace section. KMM plugin requires Kotlin 1.3 and above.

Once the plugin is installed, restart AndroidStudio and create a new Android application and select KMM Application in project template. Take a look at the following image.

Select KMM application in project template
Select KMM application in project template

Once you select the application you need to provide few more details like Application name and name for your Android, iOS and shared module. Once you provide those details you will have your project created. I have name my project KMMNovelCovid and got following directory structure after project creation.

KMM Directory structure
KMM Directory structure

You are all set now, and ready to code!

3. Problem statement/Use case

We have take a good enough problem statement to test the all typical Android and iOS project paradigms and complexities.

We want to build

  • A simple app which displays list of covid 19 affect countries.
  • Data will be fetched from remote server.
  • Fetched data will be displayed on user’s device.
  • Application will be developed using native components.
  • Test cases needs to be written.

Following image will help you to visualise what we are developing.

Visualize application UI
Visualize application UI

4. What are we sharing?

On the basis of above points following is the diagram how we will develop our shared module.

Shared module diagram
Shared module diagram

Let’s spend some time to understand this diagram.

In the bottom layer I have kept the Ktor. Our HTTP client. Ktor under the hood uses HttpURLConnection and NSURLSession for Android and iOS applications respectively. It has provision to configure everything like retry and timeout mechanism, adding certificate and public pins for security perspective. On top of that it does support some JSON based ORM libs e.g. Moshi, Jackson and Gson. Also Kotlin team has come up with their own serialisation lib i.e. Kotlinx Serialisation. We are using Kotlinx Serialisation for our project. Most importantly Ktor also support Kotlin Coroutines. Isn’t is amazing?

Now the network layer is directly used in a class named NovelCovidAPIClient.kt. This class has sole responsibility of connecting to remote server using core ktor classes , parse the json response and send it back to the consumer class.

NovelCovidAPIClient.kt has direct access to entity/data classes like CountryItem.kt and CountryInfo.kt. These classes holds the JSON data in form of class properties.

Also notice the independent block in the above diagram. That class allows you to fetch the OS information per platform. I will show you how expect/actual mechanism works where you can have a code in shared module and yet have different implementation for your Android and iOS application.

5. Configuring :shared module

Inside :shared module you need to open build.gradle.kts file and add some dependencies as shown in following code snippet.

See how the various source sets i.e. commonMain, androidMain and iOSMain is created. Inside each source set we are adding required dependencies. These dependencies will be ultimately used for writing the network layer.

Also note the property i.e.packForXcode . This property is doing a phenomenon task of creating .framework file for iOS project.

6. Writing a shared networking client

Now we need to create the shared class which makes network call. We call it NovelCovidApiClient. Checkout the code snippet and see how we are writing that class in Kotlin.

In the above code snippet you can also see how we are configuring kotlinx.serialization lib to parse JSON into CountryItem and CountryInfo data classes.

Now you can either use it in a repository type of class or use the class directly. Having this class as a part of repository class is a nice idea because it decouples the dependency on Ktor from the main application.

7. Consuming shared networking class in Android

To use this class in Android you can typically use Presenter or ViewModel. The beauty of KMM is it doesn’t impose anything on the platform. Your ViewModel class can typically look like following.

It’s pretty straight forward. Didn’t I say that in the beginning. And this is the reason the for Android engineer it doesn’t change anything.

Now this view model class can be used on Fragment or Activity level. KMM is not in scope while you use instance of view model on any of this view layer. UI layer is totally unaware of existence of KMM

8. Consuming shared networking class in iOS

Now you, may not be an iOS engineer. But to give you a complete idea how KMM can be used in iOS, let me just cover how this shared networking class can be used. Just like Android you can either consume the class directly or wrap it around some class. Checkout the following gist which will give you some more information how I have used this class in iOS.

That’s it! Job done!

Now let’s take some time to understand, how everything is coming together.

There are two factors which is making all this possible. The KMM plugin and a custom gradle task. Refer to packForXcode property in :shared:build.gradle.kts file in step 5. KMM plugin configures this task in your Xcode’s build phases. So every time you run the Xcode build and trigger the iOS build, the packForXcode will run and it creates a .framework file for you. KMM plugin also link and embeds this .framework file in your Xcode settings. This comes for free and without any efforts, because all this happens automatically by KMM plugin.

And while packForXcode task is running it actually transpiles all Kotlin code into Swift and ObjectiveC header files.

Targeting different implementation per platform

Let’s imagine that we want to get the OS’ name and OS version. But we want to keep this code in shared module. How can you achieve this. KMM allows you to define the expectation using expect keyword. What ever you define with expect keyword it is then expected that the actual implementation will be provided by an Android and iOS projects.

expect

It’s kind of instruction to KMM compiler that expect it’s implementation later on and it won’t be inside commonMain source set. Later on androidMain and iOSMain source set will provide it’s actual implementation.

actual

Both androidMain and iOSMain provides implementation using this keyword. In principal it all seems like declaring abstraction using expect keyword and later on have the implementation using actual key word.

In following code snippet you can see expect/actual in action.

Android both Android and iOS can call this function just like any other function from the shared module.

Testing

Testing is very crucial parameter to evaluate the capability and potential of KMM. Nowadays every engineering knows the significance of unit testing and very serious about it. While I tried to write a test case, it came very natural to me without any faff. I used popular Mockito framework as well. I used this mocking library to mock the core http client. See the following diagram and know how I wrote unit test around the share networking client.

Unit testing Shared API client
Unit testing Shared API client

What if my project is not a green field project?

Setting up and using KMM with the new project is very easy. But let’s be realistic. You cannot expect that in whole Kotlin community you will always start with new projects. What if you have existing project and still want to use KMM. Following is some guideline shared by JetBrains’ Kotlin team in Kotlin 1.4 event held in 2020.

Use KMM in existing project. Reference from Kotlin 1.4 event

Is KMM ready for production?

After learning about this exciting framework and approach, I am sure you can’t wait this to start working on this. But hang on, hold your horses. Because you may want to know of everything we understood is actually stable and ready for production usage. Following table will help you understand the stability.

KMM Stability guide
KMM Stability guide

References

I found lots of useful information from following links and I am sure you will find these links useful too.

Presentation video

I also gave a talk along with my colleague Rohit Jankar on this earlier this month. Please checkout the video

That’s all I have to say about KMM. Happy code sharing to you. 😄

--

--

Hardik Trivedi
Globant
Writer for

Android Engineer. Author of “Kotlin Blueprints” and “Android application development with Kotlin”.