Use Kotlin to share native code among iOS, Android
When you try to deal with the across platform codes. You need to solve 2 things, one is the architecture of how to share the code, another one is how you share. Well, different languages might have different techniques. But in Kotlin, you can use multiplatform projects to share the code. And via kotlin native, you can even expand the support to iOS and Android, I mean, natively.
An example of supporting code sharing among iOS, Android, JVM and JS is added in this repo.
1. Goal
We want to use XCode and Android Studio to edit the native app while using another IDE to edit the sharing code part. (But you can use Android studio for editing the KN code as well because they use the same language and the setup will be ready.)
- I saw some setups. They use root folder as a whole gradle project which will affect the Android project structure been displayed in the android studio because it will add some noise there.
We want to share more code between iOS and Android.
- The main hurdle is the platform-specific API. We can make them as
interface
and still shared the logic around them. But here we will usekotlin multi-platform
approach to make the code more elegant. - Think of an API like this
UserService.getAllorNull()
, then your native side just need to bind the result to the UI. Even though theHTTP
call is different across platform. But all the exception handling and data processing around the http call are the same and could be shared.
- The main hurdle is the platform-specific API. We can make them as
We want to have a clean structure where everything related should reside together.
- I mean for the gradle phase as well. Such that,
android
folder is only for Android,ios
folder is only for iOS. The root folder is for all projects. And the gradle settings forKN-android
should be in theandroid
folder as well as theiOS
side.
- I mean for the gradle phase as well. Such that,
We want to test the Kotlin native code as well.
- It’s native project so anything native can be tested via the strategy on that platform. But what about kotlin native part, what about the
common
code? What about the kotlin native platform specific code forandroid
andios
? Yes, we have that part covered as well here in the example.
- It’s native project so anything native can be tested via the strategy on that platform. But what about kotlin native part, what about the
1.1 What about I don’t need to care about the platform specific implementation
If all you need is the kotlin-stdlib
, and no platform specific code to write. Then you don’t need to use this setup. You can simply remove the android
and ios
folders from the Shared
. And let the common
just outputs an iOS framework for the XCode project to consume. For Android, embed the source code in Android studio to make it as dependency then it’s fine.
2. Folder structure
- ios: XCode project
- android: Android Studio project
- common: Common code that is about to share across platforms without any change.
- platforms:
- ios: platform specific API for iOS
- android: platform specific API for Android
Very easy to understand. One interesting thing here is in the common
folder, besides the common
folder. What’s the platforms/android
and platforms/ios
folder for? Well, they are for platform-specific API.
2.1 How to consume the lib
- Android related code will be shared via simply including the according module in the android project.
- iOS related code will be shared as an iOS framework because Kotlin native will generate that. We will then add it in the XCode building phase. You can see more details in my another blog.
2.2 Background knowledge for Kotlin multi-platform project
Let’s say you want to have an HTTP
kotlin class where you can do the normal GET
, POST
thing, but the HTTP
implementation is different across platforms. If you use the old school interface
way, you need to declare an IHTTP
interface, then implement it twice in android and ios. Then inject it at runtime to make it work.
But via using the Kotlin multi-platform project, you don’t need to inject, the compiler will only pick up the piece of codes depends on your building target. If you build for Android, it will only grab the Android implementation.
It currently works for jvm
, js
and kotlin native
, oh, that’s a nearly-all-platform code sharing tech right? :D
And it’s very simple.
You need to expect
an implementation of your common
code.
1 | expect class Platform { |
Then implement the actual code in somewhere else, like android
.
1 | actual class Platform { |
Or in ios
:
1 | actual class Platform { |
Then with some proper setup in gradle, it will work flawlessly.
2.3 How to code the platforms-ios
Oh well, you may think that old school interface
may better in terms of iOS because you need to implement the iOS API specific thing in swift or obj-c then pass it back to kotlin native. But that is not true. Because there is a 1-to-1 API match in kotlin native such that you can implement the iOS specific API in kotlin as well. And it has the same signature which means you can reuse all the existing knowledge. And kotlin and swift are very similar. And from v6, the building phase will link some of the iOS API (you need to build the others) for you if you are on a Mac.
Which means in a ideal world, your swift side just need to care about the UI part while all other logic will be handled in the Kotlin native side, shared across platform and tested well.
3. About the example
All the code for setup can be found in this repo.
https://github.com/Albert-Gao/kotlin-native-mobile-multiplatform-example
Sample
class is for code that is sharing across platforms (Which means you have to use API fromkotlin-stdlib-common
).Platform
class is a class which has been implemented twice for different platforms for showing the platform API case.Open
android
folder from the root in Android Studio, run the app, it will show a string from the:shared-android
project.Open
ios
folder from the root in XCode, run the app, it will show a string from the:shared-ios
project.
In fact, the native app retrieves the string by invoking the method from the Sample
class. And the Sample
class invokes the method from Platform
class to get the string. When you build an iOS framework, the KN compiler will use :platforms-ios
to build along with :common
. And when you consume it in android project, the setup will use :platforms-android
along with :common
. No injection, no affection on the code structure, just that simple. Thanks to the Multi-platform project
setup from kotlin.
It is a perfect example for showing how to share the code when you have to deal with the platform API.
Hope it helps. Thanks.
Thanks for reading!
Follow me (albertgao) on twitter, if you want to hear more about my interesting ideas.