The Magic of Kotlin/Native: Part 3
Kotlin/Native Series
1. The Magic of Kotlin Native: Part 1
2. The Magic of Kotlin Native: Part 2
3. The Magic of Kotlin Native: Part 3 ( You are here)
In the last part of the Kotlin/Native series we are going to create a very simple app that has its core logic in common code but uses the native platform’s abilities to display it on the respective devices.
The application that we are going to create is a simple hello platform app. Its going to work in iOS, Android, JVM and even on a Webpage using the java script plugin.
- For iOS we will use the Kotlin/Native plugin
- For Android - kotlin-platform-android plugin
- For JVM - kotlin-platform-jvm plugin
- For JS - kotlin-platform-js plugin
The common code would use koltin-platform-common plugin.
All said and done your project structure would look something like this
At this point in time JetBrains does not have a single tooling that you can use to shuffle between the .swift files for iOS and .kt for android so we are going to be shuffling between Android studio and Xcode.
The Common Code
Before checking out the code that I’ve put in this module ask yourself this question
What can comprise common code?
Well IMO anything that falls in the following categories can be bundled together and put at a common place
- Models
- Networking Classes
- Contracts
- Business Logic
- Validations
This list is by no means exhaustive and you can always extend it. Not only would that reduce the size of your organisation’s code base but prevent things like this :
Now lets have a look at the files inside ExploringMultiPlatform-common
module.
package demo.multiplat
expect class Platform {
val name: String
}
expect fun getPlatform(): Platform
Above is a snippet from Platform.kt
. Take a close look at the expect
keyword. Any module that is going to depend on this module would need to implement the classes and the methods that are marked as expect
.
package demo.multiplat
fun sendGreeting(platform: Platform, name: String): String {
return "Common: Hi $name, Welcome to ${platform.name}"
}
This is a snippet from Common.kt
As you can see it simply takes a Platform object and prints out its name. This corresponds to the business logic that every application has independent of its platform.
Android Implementation
Let’s create a module ExploringMultiplatform-android
which will be containing our android related stuff.
This is how your build.gradle
should look like:
apply plugin: 'com.android.application'
...
apply plugin: 'kotlin-platform-android'
android {
...
}
dependencies {
expectedBy project(":ExploringMultiPlatform-common")
...
}
This essentially tells the compiler that this module is expected to implement the common module.
Let’s take a look at the android implementation of Platform.kt
package demo.multiplat
actual class Platform {
actual val name: String
get() = "Android"
}
actual fun getPlatform(): Platform {
return Platform()
}
Notice the keyword actual
. This keyword corresponds to the expect
keyword we defined earlier in our common module.
Note: You need to have the same package name for all expect-actual counterparts otherwise it wont work.
All the heavy lifting is done at this point. You can start using the sendGreeting
method from your common code by simply importing it.
iOS Implentation
So finally the moment you’ve all been waiting for. Kotlin and android have coexisted for years now. Kotlin and iOS, now that’s exciting.
Similar to android, create a gradle file ( yeah i know creating gradle files for iOS project sounds strange but stay with me a bit). Now to make things clear this gradle file will not build your actual iOS project. Instead this will create the necessary artifacts that you will need to import into your project using Xcode. And all this happens thanks to the Kotlin/Native plugin.
If you’ve gone through the Part 2 of this series you can see how to convert .kt
files to an apple framework. Well thats exactly what the Kotlin/Native gradle plugin here does internally.
plugins {
id "org.jetbrains.kotlin.konan" version "1.3.0-rc-190"
}
konanArtifacts {
framework('KMulti', targets: ['iphone_sim', "iphone"]) {
// Enable multiplatform support for this artifact.
enableMultiplatform true
// Enable compiler optimizations (true/false).
enableOptimizations true
// Enable debugging for binaries generated (true/false).
enableDebug true
// Print all parameters during the build.
dumpParameters false
// Print time of compilation phases (equivalent of the `--time` command line option).
measureTime false
}
}
dependencies {
expectedBy project(":ExploringMultiPlatform-common")
}
Similar to android’s gradle we are expecting this module to implement our common project.
The konanArtifacts
block creates the actual framework depending upon the given targets.
package demo.multiplat
import platform.UIKit.UIDevice
actual class Platform {
actual val name: String
get() =UIDevice.currentDevice.systemName()
}
actual fun getPlatform(): Platform {
return Platform()
}
As you can see I can even import UIKit and other iOS(macOS) libraries.
Running this module will create KMulti.framework
files for all the targets mentioned in the build.gradle.
Remember I told you there isnt great tooling for simultaneous editing of swift and kotlin files. Just open up Xcode and import the generated framework file and you are good to go.
Your ViewController will look like this when using the KMulti library
import UIKit
import KMulti
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel!
@IBAction func clicked(_ sender: Any) {
let greeting = CommonKt.sendGreeting(platform: PlatformKt.getPlatform(), name: tf.text ?? "No Name")
label.text = greeting
}
@IBOutlet weak var tf: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
label.text = ""
}
}
Your final results should look something like this
I will leave the JavaScript and JVM modules as an exercise to the reader.
You can find the source code for the above at :
There are tons of resources for multiplatform development on the Kotlin official webiste.
- https://kotlinlang.org/docs/reference/multiplatform.html
- https://kotlinlang.org/docs/reference/js-overview.html
- https://kotlinlang.org/docs/tutorials/native/mpp-ios-android.html#creating-ios-application
- https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#setting-up-a-multiplatform-project
As always thank you for reading and clap if you found the article helpful.