Kotlin Multiplatform and Flutter are two of the hottest multi/cross-platform app frameworks and are maturing quite fast. Both help you to reuse code when developing apps for Android and iOS. However, these platforms are very different and serve distinct purposes. Having worked with both, I'm going to share what I consider to be each one's strengths and weaknesses.
Kotlin is a great choice for developing mobile apps. Its conciseness, simplicity, and expressivity allow you to write correct and readable code effortlessly. Kotlin is the suggested language if you are starting a new native Android Project. Hence, if you have to target Android devices, you will probably end with the Android business logic written in Kotlin. Now, imagine being able to put your Android's business logic code, almost untouched, inside your iOS project as an iOS Framework. KMM is the best tool to do this right now and is being used by companies like VMware, Philips, and Netflix.
In KMM, you have a shared folder that is completely reused between platforms. Most of the business logic will be platform-independent. But, when you need to write code that depends on native/system libraries, you can count with KMM's expect/actual keywords.
With this mechanism, a common source set defines an expected declaration, and platform source sets must provide the actual declaration that corresponds to the expected declaration. This works for most Kotlin declarations, such as functions, classes, interfaces, enumerations, properties, and annotations.
Curious for how it works? Look at this code:
// Shared (Common) expect fun randomUUID(): String
// Android import java.util.* actual fun randomUUID() = UUID.randomUUID().toString()
// iOS import platform.Foundation.NSUUID actual fun randomUUID(): String = NSUUID().UUIDString()
(Available in kotlinlang.org/docs)
Very straightforward, right? This way, the randomUUID() function can be used from reused code (common code), with the correct implementation being provided for each platform during compilation. Then, common code is provided for each platform as an Android module or iOS Framework.
Flutter is a cross-platform framework to target iOS and Android with a single codebase. Google calls it a "UI toolkit for building beautiful, natively compiled applications for mobile, web, and desktop". One of the superpowers of Flutter is that you can design almost any interaction or animation and have it running the same way in Android and iOS. No need to make special adjustments or to recreate the designed user interface using native platforms. For those who are looking to innovate in UI space or don't need to make strong use of native features, Flutter is a strong choice.
Flutter is very easy to use and has a really fast hot reload. It is nice to see your mobile UI rendered in almost real-time in an emulator/simulator as you code. It's not the best choice if you depend heavily on native features that don't have an existing library, because otherwise you may have to spend a lot of time making plumbing code for Flutter's platform channel. Another weakness is that the native UI components are recreated in Flutter's engine. This means that if a new OS version is released with new UI components, you will have to wait until Flutter catches up to use the newest resources.
Yes, you're reading right. I worked with KMM for shared business logic between iOS and Android + Flutter for UI in a real-world app, that is yet to be launched. That way, we unified our low-level network code and business logic between platforms with KMM, leaving Flutter with only the UI layer of the app. I will detail the design decisions and how everything went in a next post.
- Already have existing native-specific code to be reused.
- You care about having the most updated native components and want to have a 100% native look and feel on every new OS version.
- You want to incrementally share code between platforms on an existing codebase.
- You don't need to publish a desktop or web version of your app.
- You don't want to depend on Flutter engine's implementation on each platform.
- Your project isn't going to be released very soon, or you don't mind about KMM being in alpha status right now.
- Your app is strongly tied to multi-thread or it has background processing needs.
Beware: KMM is currently in alpha and the APIs may change until it hits stable. Kotlin native memory management is being replaced (important for iOS). You will need to study how it handles memory management, concurrency and immutability to correctly implement multiplatform code for now. Check: https://kotlinlang.org/docs/native-concurrency.html#global-variables-and-singletons
- You are in a small team and don't have resources for two native UI codebases.
- Your app depends mostly on simple API and database calls, a common use case in mobile apps. In this scenario, you can avoid writing Flutter's Platform Channel code as you won't need to interact with native code.
- Your app has a custom UI or you are innovating in UI space.
- You target Web and Desktop besides Mobile and want to have a working solution for these platforms right now.