Kotlin Multiplatform (KMP) is a technology stack which allows you to share Kotlin code between Android, iOS, desktop and additional platforms. It’s one of the hottest topics in Android community today and it has the potential to change the way we approach mobile development.
However, even though there is a lot of talk about Kotlin Multiplatform, it’s not that simple to find reliable and up-to-date information about this technology. That’s why I asked Aleksey Mikhailov, CTO of IceRock Development agency and one of the leading KMP experts in the world, for an interview. IceRock have been using KMP in production for more than two years, so, by now, they have already accumulated a considerable experience with this relatively new technology.
You can watch the entire interview on my YouTube channel, but it’s in Russian. Therefore, unfortunately, only a small portion of my readers will be able to enjoy the entire conversation. However, Aleksey shared so much important information that I felt obliged to share it with all my readers. Therefore, in this post, I’ll summarize the most important parts of our conversation.
We have Kotlin Native, Kotlin Multiplatform, JetBrains has just released alpha of Kotlin Multiplatform Mobile, and there are probably more “Kotlins” that I missed. Could you speak to the relationships between these entities?
Kotlin native is a compiler. It compiles Kotlin code into appropriate “native” binary code for specific platforms: iOS, MacOS, Linux, Windows, Android, etc. The result of this compilation is a binary executable that can run on the target hardware directly, without any virtual machines.
Kotlin Multiplatform is essentially a technology which aggregates different Kotlin compilers together. These are Kotlin Native, Kotlin JVM and Kotlin JS. All of them compile Kotlin code, but produce different artifacts. So, KMP is a set of tools, language instructions and Gradle plugins that allow you to set up a project that contains some “common” code, alongside platform-specific code for iOS, Android, Windows, etc.
In addition to the fact that platfrom-specific parts of the code don’t “exist” for other targets, they also have direct access to “native” APIs of the respective platforms. In Android, KMP has access to the entire Android SDK. In iOS, it can integrate with iOS frameworks like Foundation, UIKit, etc. In addition, platform-specific parts can import platform-specific third-party dependencies using package managers like CocoaPods.
Kotlin Multiplatform Mobile (KMM) is just part of KMP. See, the entire multiplatform is very big. It has many targets and, consequently, many stakeholders. To concentrate efforts on Android and iOS, JetBrains built a new team and hired people with mobile experience. They will collaborate closely with Google to push KMP into mobile space. KMM task force already produced a new plugin for Android Studio, dedicated website with documentation, case studies and more…
So, KMP, except for aggregating different Kotlin compilers, also prescribes higher-level project organization structure?
KMP uses different SourceSets. There is commonMain, androidMain, iosMain, etc. There are also different test SourceSets. In addition to just separation of SourceSets, KMP includes additional pair of language constructs
expect is a declaration of some class, function or another language construct in one of the SourceSets. For example, we can write in the common code
expect class Logger. Following this declaration, we can instantiate and use this class in the common code just like any other class. However, there is no real implementation of this class in the common code. Instead, the implementations will be provided in platfrom-specific SourceSets as
actual class Logger. This way, for example, we can use Android’s Logcat in Logger’s implementation on Android, while employing different approach on iOS (because there is no Logcat API in iOS).
Another prominent KMP expert says that “Shared UI is a history of pain and failure. Shared logic is the history of computers”. As far as I understand, KMP didn’t intend and, maybe, still doesn’t intend, to target UI development. So, it’s a philosophy for writing non-UI logic. This sounds reasonable because UI logic lives according to a different set of rules than the rest of the app. Is my understanding correct?
The concept of multiplatform doesn’t imply that you can’t share UI logic. It’s very flexible, so you control what’s shared and what’s not. You can use multiplatform to share just one complex mathematical computation, or you can use it to share everything, including UI.
For example, that’s what we did with our library moko-widgets. Even though it’s relatively immature, we’ve already used this approach in two projects. The bigger one is available in both stores and I don’t think anyone can notice that this application employs “UI tricks” (unless you know what to look for).
So, moko-widgets basically work like ReactNative, providing a “proxy” to respective native UI elements on all platforms?
Let’s imagine that Jetpack Compose is released and it provides multiplatform UI for both iOS and Android. Do you think there is a reason for Jetpack Compose and moko-widgets to coexist?
There is a fundamental difference between sharing UI using Jetpack Compose and moko-widgets.
moko-widgets represent truly “native” UI. Therefore, if at some point Jetpack Compose will become Android’s “native” UI toolkit, then we’ll just change the implementation of moko-widgets for Android target to use it under the hood instead of the old UI toolkit.
However, Jetpack Compose by itself will never become “native” for iOS because, as far as I know, it doesn’t support “native” iOS widgets. If it will, that would be awesome and maybe we’ll refactor everything to Jetpack Compose. But, currently, the limitations of Jetpack Compose are the same as Flutter’s limitations.
So, there is a reason for moko-widgets and Jetpack Compose to coexist because Compose basically works like Flutter. In fact, I think that Compose combined with KMP are direct Flutter’s competitors.
There is just one problem, though, which might take a long time to solve. Flutter has “hot reload”. It’s awesome and makes you very happy when you code. It’s notably different with KMP.
When iOS devs use KMP, they hate the person who made them use KMP. At least until they learn how to work with this tech. Then, they just sit grumpy, waiting for builds. For Android devs adopting KMP is much simpler. For example, our Android devs didn’t oppose KMP in the least. So, iOS devs suffer a lot initially, and then they suffer less, but still suffer. Kotlin Native builds are very slow and on one of our projects even incremental build takes more than four minutes. So, four minutes with KMP as opposed to less than a second with Flutter. It’s a big difference and that’s where Flutter has an edge.
Said all that, in Breslav’s latest post [Andrey Breslav, chief language designer for Kotlin], towards the end he mentioned that in the future it would be great to apply code changes without project rebuild. In other words, “hot reload”. So, if they indeed look into this direction and will implement this feature, then Compose will be able to compete with Flutter. Or, at the very least, they’ll need to reduce build times because even with KMP on Android the feedback loop is much longer than with Flutter.
It sounds like if I, as an Android developer, want to write a new application which doesn’t need to be ported to iOS (at least right now), then I can already use Kotlin Multiplatform without much pain.
You won’t experience any pain at all. You’ll just start thinking more about what constitutes common code and what constitutes platfrom-specific code. This will probably lead you to a closer examination of app’s architecture because you’ll want to extract platform-specific features into smaller reusable components.
Then, in the future, you might want to compile some modules for iOS. If you’ll notice that you have, say, just three classes in androidMain source set, then you can google how to achieve the same functionality in iOS, write the respective
actual implementations and that’s it. The next stage would be to integrate these modules into iOS app, if you’d like to.
Flutter team seems to be very apt in promoting Flutter into masses. They market it heavily, of course, but they’re also strong in PR, establishing relationships with developers and engaging with external contributors. I feel that Kotlin Mutliplatfom lags behind considerably in this context and Kotlin team doesn’t do enough to promote it. If you’d need to criticize marketing approach taken by Kotlin Multiplatform team, what would you tell them?
Well, first of all, Kotlin team are aware of my opinions because I visited them more than once, we had conference calls, so I told them what I think. It’s not a secret.
I totally understand why JetBrains doesn’t promote KMP as eagerly as, say, Flutter is promoted. This tool is not mature enough yet. It’s not experimental anymore, but it’s still in alpha. Therefore, some things aren’t polished and there will be changes in the future, so one needs to be ready for a bit of periodic pain if they use KMP today.
If JetBrains would bring lots of developers into the ecosystem at this point, most of them would look at the current state and just leave. Enthusiasts, who would accept the risks and help KMP mature would stay, but these people are already joining anyway. They hear about KMP, join Kotlin Slack, start using the framework and provide feedback. Then Kotlin product managers get into contact with these enthusiasts to gather more information, and they’re open to hear any criticism.
Kotlin Multiplatform should mature and become simpler, especially for iOS developers. It’s a matter of improving developers’ experience. Once the barrier for entry is lowered, they’ll probably start promoting it more.
Kotlin Multiplatform at IceRock
When did you find out about KMP?
In the summer of 2018 I came around Kotlin Native and played with it a bit. It felt cool and worked, but there were many pain-points and it was inconvenient. Back then it was just version 1.2. I built a demo with it and realized that’s exactly what I always wanted to have. It’s similar to java2objc tool from Google, but better. Instead of just translating Java to Obj-C, you directly compile Kotlin into binary code and have tools that support “direct” iOS development.
How many projects have you built using KMP since then?
I don’t know for sure…
Let’s say, more than 10?
Yes, more than 10 for sure!
You also released quite a few KMP libraries. Names of all of them start with “moko”. What’s “moko”?
There was a library named Anko, which stands for “Android Kotlin”. So, when I searched for a simple and descriptive name for our libraries, I thought of “moko”, which stands for “mobile Kotlin”.
A provocative question, if I might. Do you still write native Android and iOS applications for your clients? If yes, then in which circumstances?
Yes, we still write native applications.
First, there are legacy projects that we maintain which date back before KMP days. We wanted to refactor some of these projects to KMP, but that requires green light from the clients. However, in most cases, clients want new features that they currently need and aren’t willing to spend resources on refactoring.
Sometimes we also adopt external projects from other teams. These are usually native as well, so we roll with that. Interestingly, some of these projects come with small modules written in KMP, but the degree of code sharing isn’t as high as we achieve at IceRock.
It’s important to understand that our developers are still Android and iOS developers. The fact that they also know KMP doesn’t take away from their native development skills. They still need to be experts in the underlying platforms. It’s different, from, say, Flutter, where developers can pretty much forget about Android and iOS worlds.
Alright. So, in general, if you start a new project today, you will use KMP?
Yes, if there is no explicit objection from the client. For example, some clients want the project to be maintained by their own teams after we complete it, so they ask for specific technologies. In other cases, a client might need just iOS application and then there is no reason to use KMP then.
Can you estimate how much effort does KMP save as compared to writing two native applications?
Well, it depends on the project.
Some projects don’t have much UI, so the common module can become very prominent. Then it’s a considerable economy. In some cases, we can reduce the cost of one of the platforms by 50% or even more.
On the other hand, if app requires much custom UI, then there won’t be that much common code. In these cases, you need to spend a lot of time on building beautiful, custom UIs for each platform according to design specs, so the benefits will be considerably smaller.
Comparison to Other Cross- and Multiplatform Solutions
You told me that you had had experience with Cordova, but didn’t like it. Have you considered some other approaches as well?
I looked into Xamarin at one point. What stopped me was the fact that we would need to pivot the company to C# and look for C# devs, and there aren’t many of them around. In addition, one of our guys already had hands-on experience with this framework, and he said that it’s far from ideal. So, we didn’t explore Xamarin any further.
Then we tried ReactNative, even set up a mini-team. In total, we completed three or four projects using this technology. It didn’t scale for us due to framework’s technical issues and our preexisting conceptions and biases. In addition, except for one developer who pushed this technology, other developers didn’t really want to migrate from native to it.
Provocative question, if I might: have you looked into Flutter?
Yeah, I tried Flutter in 2017 and then in 2018. I liked it overall. However, adopting Flutter would mean that we need to pivot the company to Dart. This would make sense only if we would be absolutely sure that’s the direction we want to go and also accept the fact that some people would leave.
My biggest issue with Flutter was that I couldn’t get a native UI with it. See, I’m a big proponent of native UI for users because they value it.
However, I did use this framework for quick prototyping during sales negotiations. I’d spend a day and have a bunch of styled screens that show mock data with basic navigation between them. These prototypes were good enough to be demonstrated to prospective clients.
Just one day for an app, even a simple one? Sounds very productive. So, would you say that Flutter’s “ethos” that it’s very quick for development is correct?
Yes, Flutter is indeed pretty quick. Its “hot reload”, its simplicity when it comes to UI construction, these features are very appealing to developers. That’s why many devs take that path. Well, not just because of that, but also because Google switched on their marketing machine and promote Flutter. Really, you hear about Flutter everywhere nowadays.
So, yes, Flutter allows for quick and simple UI development, but it’s totally different language and no option for native UI. These were deal breakers for us and that’s why we didn’t adopt it in the company. Also, I came around KMP around that same time.
I believe that at this stage it’s already clear that Flutter team “lures” Android developers into Flutter ecosystem. JetBrains and Android team at Google, on the other hand, want to “lure” Android developers into Kotlin ecosystem instead. In your opinion, what’s the future of Kotlin Multiplatform and how will this “battle” against Flutter go over the next half a year to a year?
The next half a year to a year? Nothing will change. Flutter will continue to attract more and more people while Kotlin Multiplatform will keep maturing.
KMP will improve in technical aspect and, gradually, more developers will join the ecosystem, but there will be no drastic changes. Given the pace of KMP evolution so far and how JetBrains operates, this is not a quick process. So, again, over the course of the following year there will be mostly technical improvements. For example, a new compiler. I hope that it will finally show a major performance boost in Kotlin Native compilation. I also hope that we will see better and more stable support for code debugging on iOS. Like the ability to put a breakpoint and see the values of various variables in that scope.
That’s all folks.
Keep in mind that the above is not a full transcript, but just my amateur-ish translation of what I considered to be the most important points. Since I learned quite a bit from this conversation with Aleksey, I really hope that I succeeded in transferring at least some part of Aleksey’s very insightful answers in this post.
Allow me to use this opportunity to thank Aleksey for his time once again. I really appreciate the fact that he agreed for this long interview.
By the way, during our conversation, Aleksey mentioned that IceRock provides consulting services to companies which either consider KMP adoption, or already started using this technology in production. Based on what I heard from him, I’d say that if you want to jump onto KMP train, IceRock can be very valuable partner on this journey. [No, they didn’t ask me to write this].
As usual, thanks for reading and you can leave your comments below.
4 comments on "Kotlin Multiplatform: Expert Opinion and Comparison to Flutter"
Thanks, it’s very clear simple and useful.
Very interesting interview.
I’m a little bit confused by what do you guys mean by “native UI”? As in the following sentence:
“My biggest issue with Flutter was that I couldn’t get a native UI with it. See, I’m a big proponent of native UI for users because they value it.”
What is that sentence about? Does UI produced within Flutter differ somehow from UI produced within pure Android? Does it look or work in a slightly different way? Or is it just about the language that by “native UI” you mean that it’s not being done in a “native” (aka. traditional) way on pure Android?
Thanks in advance for clarification.
The bottom line is that Flutter’s UI both looks and works in a slightly different way, even though Flutter team does invest effort into making Flutter apps as similar as possible to “native” ones.