Intro
JetBrains' flagship framework for mobile platforms, Kotlin Multiplatform, has come a long way, evolving to offer the promise of "write once, run everywhere." The framework allows you to share business logic across platforms, which required native UI implementations for each platform. With the advent of Compose Multiplatform, JetBrains has taken this concept even further, enabling a true "write once, run everywhere" experience. Built on top of Kotlin Multiplatform, Compose Multiplatform allows developers to share both UI and business logic across all supported platforms, including Android, iOS, Web (via Wasm), and Desktop (via JVM).
While this is a major leap forward, it’s important to acknowledge that Compose Multiplatform doesn't fully solve the challenge of a one-codebase approach for all platforms. There are still some gaps that developers need to address. JetBrains has done a commendable job in creating a unified experience, but platform-specific adjustments are often necessary.
One of the key tools in achieving this is the expect/actual mechanism. Simply put, this approach allows developers to define common logic in the "expect" block, while providing platform-specific implementations in the "actual" block. This means that if Compose Multiplatform doesn’t meet the needs of a particular platform, developers can define platform-specific functionality with the actual keyword.
As a result, it’s mandatory to have an actual function for each platform in your Compose Multiplatform project to fill these gaps. This ensures that your application can fully leverage platform-specific features while maintaining the core benefits of code sharing
The Gap?
You may have to write expect/actual functions for each platform. For instance,the Google's androidx-libraries made for KMP are usually made to support just the mobile platforms (and maybe for JVM) however the Wasm targets lack. Hence having duplicate actuals for iOS, Android, & Desktop just doesn't comply to standard coding practices and can result in code repition.
An example, showing the RevenueCat SDK used in commomMain results in a
Could not resolve
error for Wasm and Desktop targets
Gradle module to the Rescue
To address this issue, we can create simple, dedicated modules and designate the root directory as a source root. This structure will house all the common code shared across specific platforms, providing a clean and effective solution. Let’s use the Room Database library as an example, which works across iOS, Android, and Desktop (JVM) platforms
We create a nonWasmModule. While the name may seem unusual, it serves its purpose. This module contains just one actual function for the expect method (defined in commonMain), and for Wasm, we can use the web’s local storage as an alternative. This approach solves the problem.
Similarly, for the mobile platforms (iOS and Android), we create a mobileModule
, set it as the source root, and include the actual functions, objects, or classes specific to mobile.
Finally, we update the Gradle file at the app level to ensure the new modules depend on the common module, inheriting all shared dependencies between platforms.
Top comments (0)