Kotlin Multiplatform Mobile : IOS and Android Apps with common native code

Atul Sharma
5 min readSep 9, 2020

--

In Kotlin Native, the Kotlin code is complied into native binaries and run without any virtual machine. The Kotlin/Native has different compilers for various operating systems like macOS, Windows, and Linux.

Kotlin/Native compiler converts the Kotlin code to native binaries, therefore no virtual machine is required.

Cross platform with Kotlin/Native (Android and IOS Apps)

Using Kotlin/Native we can use Kotlin code in Swift/Objective-C and vice versa. We can create a framework for macOS and iOS from Kotlin code using Kotlin/Native compiler. This framework contains all declarations and binaries that are required by Objective-C and Swift. Kotlin/Native doesn’t use common UI , it focuses on common Business logic.

Flutter / React Native and Kotlin Native

The main difference between Flutter / React Native and Kotlin Native is, it provides common code for almost every thing except UI. We have to create UI of Android using native android code (XML based) and IOS using SwiftUI or other native techniques.

Creating a Kotlin/Native Project

Lets start with creating a simple Android project in Android Studio. While creating the Android project select the language Kotlin and name of the Application KotlinNativeExample.

Creating the Shared Module

Now we have to create a shared module, which will be used by both Android and IOS Apps. In our project directory let us now create a directory shared (Any name you can give)

Create shared/src/commonMain/kotlin directory. Now create common.kt file in commonMain directory. also create androidMainand iosMaindirectories for android and IOS specific code

in common.kt let us define a function which we will invoke from both platforms

package com.kotlinnative.shared

expect fun getPlatformName(): String

class HelloWorld {
fun sayWelcome(): String = "Welcome, ${getPlatformName()}"
}

expect function is the signature of the platform specific function, which will be implemented separately using Android and IOS specific code.

Android specific code is in androidMain/kotlin folder (android.kt file)

package com.kotlinnative.shared

import android.os.Build

actual fun getPlatformName(): String {
return "Android ${Build.VERSION.RELEASE}"
}

Similarly the IOS specific code is in iosMain/kotlin folder (ios.kt file)

package com.kotlinnative.shared

import platform.UIKit.UIDevice

actual fun getPlatformName(): String {
return "${UIDevice.currentDevice.systemName()}
${
UIDevice.currentDevice.systemVersion()}"
}

We have to add build script in shared module. create a build.gradle file in shared folder. This is a common script or boilerplate code to create libraries for different OS (Android and IOS)

apply plugin: 'com.android.library'
apply plugin: 'kotlin-multiplatform'

android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 15
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}

kotlin {
targets {
final def iOSTarget = System.getenv('SDK_NAME')?.startsWith('iphoneos') ? presets.iosArm64 : presets.iosX64

fromPreset(iOSTarget, 'ios'){
binaries {
framework('shared')
}
}

fromPreset(presets.android, 'android')
}

sourceSets {
// for common code
commonMain.dependencies {
api 'org.jetbrains.kotlin:kotlin-stdlib-common'

}

androidMain.dependencies {
api 'org.jetbrains.kotlin:kotlin-stdlib'
}

iosMain.dependencies {

}
}
}

configurations {
compileClasspath
}

task packForXCode(type: Sync) {
final File frameworkDir = new File(buildDir, "xcode-frameworks")
final String mode = project.findProperty("XCODE_CONFIGURATION")?.toUpperCase() ?: 'DEBUG'
final def
framework = kotlin.targets.ios.binaries.getFramework("shared", mode)

inputs.property "mode", mode
dependsOn framework.linkTask

from { framework.outputFile.parentFile }
into frameworkDir

doLast {
new File(frameworkDir, 'gradlew').with {
text = "#!/bin/bash\nexport 'JAVA_HOME=${System.getProperty("java.home")}'\ncd '${rootProject.rootDir}'\n./gradlew \$@\n"
setExecutable(true)
}
}
}
tasks.build.dependsOn packForXCode

Create AndroidManifest.xml in shared/main folder

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kotlinnative.shared"
/>

now Sync and Build shared module

Creating Android Build

In order to use this common module in Android we have to add this module in settings.gradle

include ':app', ':shared'
rootProject.name='KotlinNativeExample'

Add the shared module and other packagingOptions in build.gradle of Android project

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
... packagingOptions {
exclude 'META-INF/*.kotlin_module'
}

}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':shared')
...
}

Now invoke the function from shared module in Android App

package com.kotlinnative.example

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.kotlinnative.shared.HelloWorld
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
displayText.text = HelloWorld().sayWelcome()
}
}

Sync , Build and Run the code on Android device.

IOS Project

Create a new folder inside the KotlinNativeExample named iosApp and in that folder create a new iOS Project (use Swift language).

Now go to the Android studio and sync the shared module. Open the terminal, and execute the following command

./gradlew :shared:build

after build is completed you can see the build folder of shared module

Now open Xcode and goto the build phase, add a new run script using + icon on top.

add following script

cd "$SRCROOT/../../shared/build/xcode-frameworks"
./gradlew :shared:build -PXCODE_CONFIGURATION=${CONFIGURATION}

build phases must be in correct order: Target Dependencies and below that Run Script

In Build Settings search for Enable Bitcode and set its value to No

Now Build Settings search Framework Search Paths , add following path

$(SRCROOT)/../../shared/build/xcode-frameworks

Now add the framework , in general tab click on the plus icon on Embedded Binaries, select Add Other and select the framework from ../shared/build/xcode-frameworks

All the setting are done, we have to import shared in our code and use Kotlin Native function in it

Clean , Build and run on IOS device

Wow !!! we have developed our first Kotlin native application, running on Android and iPhone with common code.

You can download the source code from

https://github.com/atuljava741/KotlinNative.git

--

--

No responses yet