Mobile Code Sharing with Kotlin Multiplatform
Native mobile development for iOS and Android generally involves writing two (2) separate code bases, picking an “all in” cross platform tool, or using some form of code sharing to bridge the gap.
For long-term mobile developers, there is a sense of dread around any form of “cross-platform” due to generally negative experiences and outcomes. Then tooling and ecosystems are generally bad, the performance is often bad, etc.
There is nothing about the native tools that make them inherently better options, other than Apple and Google have huge incentives to make great apps for their platforms, and the teams that make the tools control the platforms. Other technology that intends to “keep up” needs to find its own incentives (and, by extension, funding), and needs to be very careful not to try to beat the native platforms at what they do best.
Native developers tend to talk about “cross-platform” as one concept, with all tech being rolled into “native” and “cross -platform”. In reality, all these options vary considerably and it’s important to define them appropriately so we can discuss which options are better for which circumstances.
The most concise definition of Kotlin Multiplatform I can give is as follows:
- natively integrated
- open source
- mobile code sharing platform
- based on the popular, modern language Kotlin
- facilitates non-UI logic availability on many platforms
Optional means the tech is designed to be used along with the native tech. Most cross-platform frameworks allow you to integrate them into existing apps, but are generally not designed to make that easy. “Possible” is not the same as “actively designed for”.
The optional sharing nature means it is easy to evaluate KMP in your existing apps. You can add code incrementally, and critically, if some shared code isn’t performing as expected, you can “just code it natively” without any major issues. The optional sharing nature makes KMP low-risk.
Other code sharing solutions, such as C++, JS and Rust, generally involve a bridging layer. C++ is “native”, but from the JVM you need to talk to it through JNI. That will have extra code and performance implications. The same goes for other code-sharing frameworks. They run in their own expected runtimes, with their own expected rules. Kotlin was designed to interop with the JVM directly, and Kotlin Native has been designed to use LLVM to produce actual “native” code.
For iOS, the Kotlin compiler outputs an Xcode Framework that Objective-C and Swift can communicate with directly. It looks like any other Objective-C framework, and with Swift ABI stability in 5.1, we can expect direct Swift interop next year.
Native integration dovetails with optional code sharing to reduce barriers to integration (easy to call, low-performance impact, etc) and reduce risk.
Most new languages and platforms are developed as open source. It would be very difficult to create a closed source ecosystem in 2019. Not only does open source significantly reduce the risk of debugging issues, but it also allows the community to participate in the platform development.
To help ensure good public direction and guidance, Jetbrains and Google, along with other industry representatives, created the Kotlin Foundation to help steer future Kotlin direction.
This is important.
For libraries, support, training, hiring, etc. The ecosystem you pick needs to be popular. Having a very small ecosystem introduces it’s own form of risk. Kotlin Multiplatform is currently small, but growing very rapidly. It is very unlikely to lose momentum now. There will be an early adopter impact, but there’s also an early adopter opportunity.
For teams that want to be involved in open source, and to be able to recruit developers interested in new tech, it’s a great time to get involved.
Kotlin is a changing platform, attempting to incorporate lessons from other languages and ecosystems. This will mean better productivity and safety, and a longer “shelf life” for the ecosystem as a whole. It is a future-proofed ecosystem.
Mobile Code Sharing
It is important to distinguish “code sharing” from “mono-UI” and other cross-platform technologies.
One of my own favorite quotes is:
“The history of shared UI has a lot of pain and failure. The history of shared logic is the history of computers.”
Speaking of native mobile specifically, Android and iOS are very similar under the hood. They’re both Unix-y, have files, threads, networking, sqlite, etc. If the tooling was great, and the integration was seamless, it would be crazy not to create a shared codebase for at least some of the logic and architecture of applications. You can write it once, test it once, and only pay one cost for maintenance.
Code sharing is in contrast to shared UI, and “3rd platform” architectures. Picking Flutter, or React Native, or Xamarin (Ionic or any web thing, etc) means you will make a heavy investment in that platform. They don’t integrate well with the native ecosystems. They are what we call “Big Decisions”, and stress “Capital B, Big Decisions”. Big decisions are risky. They take effort to make. You need to train/hire for another 3rd platform. You need to recode a bunch, and/or write bridge code to the native code already in your app. You will likely need to fill in gaps that don’t exist. You need to accept the risk that the primary developer of the platform may decide to stop supporting it.
For that reason, it’s very important to understand the financial incentives involved. Most of these tools are free. If you aren’t the customer, you’re maybe the product. In any case, these frameworks and tools aren’t free to make or support, so why they’re made is an important consideration. As the risk increases, the investment and reliance on that tech should decrease, which is the opposite of how most cross platform options are architected (i.e. they want you to do everything in their tool, and take on more of that risk).
As a side note, Kotlin is the preferred language for Android. In the case of native mobile, this makes Kotlin unique for code sharing. C++, JS, Rust, Go, etc can all be used, but none of them is the “preferred” language for either platform. In the case of KMP, there’s no “3rd” ecosystem. Again, going back to risk, not adding a 3rd language is important. Also, because of how Android the Operating System is created and deployed to actual devices, there tends to be a much wider range of versions and issues. Being able to avoid adding any risk to the Android side is a huge benefit.
The final important note is that Kotlin is made by JetBrains. They make some of the most popular tools for developers in a wide range of language ecosystems, but have absolutely dominated the JVM tooling world. Developer experience is critical for adoption, and if anybody else was trying to build a shared code solution at this scale, I’d say their chances aren’t great. The tooling is still in development, but if anybody can pull it off, it’s JetBrains.
JetBrains is a profitable company that sells developer tools to developers. They do not share the risk of venture-backed open source (Parse, Realm, etc). It is *possible* that they’ll sell to somebody, but there is no existential threat forcing them to do so. I started using their Java IDE back in 2000. That is ancient in the tech world. They have thrived using the old model of making and selling a product, and it’s likely they will continue doing just that.
Useful introduction to Kotlin Multiplatform resources