Kotlin Multiplatform for sharing code between native Android and iOS app

Often we mobile developers get asked a question, “Can we share code between Android and iOS app?”. After all much of the business logic remains the same regardless of platform we build for. Mobile developers ends up implementing much of exact same logic on each platform. Not only logic but, tests around that code is also duplicated. It is also challenging to ensure both apps implemented exact same logic. After all, if different developers worked on the platform, chances are logic is different causing each app to behave differently.

In this post, I will go over Kotlin Multiplatform as a solution for this problem. I will explain how Kotlin Multiplatform could help us having “common” code in one place shared between the two native apps. One of the main objective is that common code should be native to each platform and should have first class citizen support.

Problem Statement:

As an example for this use case, let’s assume that we are trying to implement an Analytics Event Logging framework. To keep things simple, let’s say the event name and property should be same on both platforms. An Event is a “common” thing for each platform. (Note: the issue could have been that each platform may have named their Event and property different, “button_click” vs “ButtonClick” etc)

In this example we will build a Kotlin Multiplatform solution that contains the common code shared between in Android and iOS app.

Settings up Android Project:

Let’s being by setting up a new Android project. Go through the new project wizard in the Android Studio and create a new Android project called “KotlinMPLogging”. Once complete, you should be able to start the app and see the “Hello World!” screen.

1. Hello World

Switching to Kotlin 1.3:

At this point, let’s configure our project to use Kotlin 1.3, Let’s configure our IDE to use the Kotlin 1.3 plugin. To do so, go to the Settings, Cmd + , > Languages & Frameworks > Kotlin Updates and pick “Early Access Preview 1.3”

Screen Shot 2018-10-14 at 12.57.31 PM

Next up, let’s update the build.gradle, of the main Project and update the kotlin version (rc-80 is the latest RC version as of this writing)

ext.kotlin_version = '1.3.0-rc-80'

Your, IDE will error out as it will not able to obtain the pre-release version of kotlin. To fix this, we would need to add maven url in the build script.

maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }

We will add this for both buildscript as well as allprojects so our app module is able to get the right version of std lib.

After these changes are made, your build.gradle should look like this:

We should also update the gradle wrapper to 4.10+ as Kotlin Native plugin requires the newer version. To do so update distrubtionUrl in gradle-wrapper.properties file

distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip

 

 

At this point, you should be able to successfully build and run the Android project. Nothing has changed so far expect for using Kotlin 1.3.

Setting up the “Common” Kotlin Multiplatform module:

Now the interesting part. It’s time to build the Kotlin Multiplatform portion. This will be shared between different platforms (iOS and Android). To keep things simple, let’s create a folder named common in current project folder.

The folder will be structured in following way:

common/src/commonMain: All the common code will be here

common/src/androidMain: Android specific code would live here, for this example we won’t have anything here.

common/src/iosMain: iOS specific code would live here, for this example we won’t have anything here.

Time to create build.gradle for this module (it will be inside “common” folder we created above).

Here, we apply the ‘kotlin-multiplatform‘ plugin. Source set dependencies are defined here. e.g. we use kotlin-std-common in our common source set.

In the commonMain, start by creating the Event interface (commonMain/kotlin/com/manijshrestha/kotlinmplogging/analytics).

To limit the complexity in this example, let’s create a AnalyticsManager interface. Idea is that Event gets reported by AnalyticsManager. Each platform will implement its own Manager and use the Event from the common code.

With this plumbing in place, we can now add real Event implementations. We will add 2 events.

ButtonClickEvent and ViewEvent 

As you can see above, each of the class have event name defined, regardless of the platform (iOS or Android) these events will have same name. Also required parameters are defined in the class so each platform will need to provide those arguments.

We could do lot more here but to keep the scope of this post limited to common code, We will leave this here and move on to platform specific implementation.

Using Common in Android Project:

Now it’s time to utilize the common code in our Android project. To do so lets include the “common” module in settings.gradle file

include ':common'

Now, add “common” project as a dependency in our app’s build.gradle dependencies section.

implementation project(':common')

With above changes, we can now provide the implementation of the AnalyticsManager. We could implement it to send Fabric Answers event or Google Analytics or perhaps to any services that you may want to call. For now, we are going to log the event in logcat using android logger.

To see it in action, we are going to update the activity layout to have three buttons. We will send separate event on each button click.

Here is the Activity where we will implement the reporting of the event.

With these changes we can run the app and see it in action.

Screen Shot 2018-10-14 at 3.21.38 PM

Screen Shot 2018-10-14 at 3.22.04 PM

When the page is loaded, we are now reporting Page_Viewed event with the page name and as we tap on each button, we get Button_Clicked events reported (above, we can see Red and Green button click events).

With android side fully implemented, it is time to implement it in the iOS app.

Building common framework for iOS:

If you take a peek at the “common/build” folder, you can see that it generated the java class files for our Android app to consume. For iOS app we need to compile it as “framework“. Let’s get this by adding the following script in our build.gradle file of common module.

With following changes in place, run the ​’​build’ task.

Screen Shot 2018-10-14 at 3.30.34 PM

We should see the frameworks being generated for both release and debug.

Screen Shot 2018-10-14 at 3.31.29 PM

Setting up iOS project:

Go through the new project setup wizard on Xcode and create a single view application.

Now, add the framework that was build from above step in our project. To do this, go to General > Embedded Binaries +

Screen Shot 2018-10-14 at 4.31.59 PM

Also, add the Framework path by going into “Build Settings” Framework Search Paths:

Screen Shot 2018-10-14 at 4.36.50 PM.png

With these changes, you should be able to compile and run the app without any issues.

At this stage, we are going to create the IosAnalyticsManger. Create IosAnalytiscManager.swift class in the project with implementation of your choice. For this demo we are going to print the Event detail in the console.

Similar to android app we are going to add 3 buttons in the storyboard and link the click action to our view controller.

Screen Shot 2018-10-14 at 4.41.11 PM.png

We will link these buttons to our view controller.

Now, run the app and we should be able to see the app in action:

Screen Shot 2018-10-14 at 4.44.57 PM

As the page is loaded, Page View Event is reported, similarly as we tap on each button the Button Clicked Event is reported. In our case, we can see the output in the console log.

Screen Shot 2018-10-14 at 4.46.12 PM

Summary:

To wrap it all up, we built “common” component using Kotlin Multiplatform plugin. We defined Event and AnalyticsManager there. We built Android app that used implemented the interface defined in the common. We then used it to repot the event. Similarly, we built iOS app, we implemented the protocol defined in common. We then used the exact same Event class defined in common to report the event.

This is just scratching the surface of whats possible with Kotlin Multiplatform. I hope this shows the potential of whats possible. I hope you found this post helpful. Until next time, adios amigos.

Sample code for this project is found in github: https://github.com/manijshrestha/kotlin-multi-platform-logging

 

References:

Kotlin Multiplatform Project: iOS and Android

 

 

 

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s