Today, I want to share a tale that many of you can relate to—diving deep into rabbit holes and the infamous yak shaving sessions. Over the past two weeks, I’ve been on such a journey, experimenting with Kotlin Multiplatform (KMP) to see if it could solve some challenges we’ve been facing. So, grab your coffee, sit back, and let’s unravel this adventure together.
The problem at hand
I’m working for a client in the health and wellness space. The mobile app we’re building, originally developed in Flutter, served us well during the initial stages, but as we aimed to scale and add more complex features, Flutter began to show its limitations.
We’re dealing with heavy processing tasks and potential on-device computation, making isolates in Flutter quite a pain. So, I decided to explore KMP to see if it could be the knight in shining armour for our app.
For those not in the know, KMP is a cross-platform application development platform. It’s relatively new and I haven’t had the chance to use it on a client project yet. And I’m going to assume you know what yak shaving is, but just in case: yak shaving refers to every little (usually seemingly unrelated) thing you have to do in order to get to the task that really needs to get done.
Diving down rabbit holes
My exploration started with a hypothesis: KMP could provide a more seamless way to handle native platform needs without the cumbersome plugin interfaces of Flutter. Inspired by the recent KotlinConf talks, I was optimistic. The promise of accessing native platforms directly, coupled with Kotlin’s growing list of cross-platform libraries, seemed like a perfect fit.
But as any seasoned developer knows, things rarely go as planned.
The yak shaving begins
The first significant hurdle was dealing with AWS Amplify for authentication. While there are native libraries for Android and Swift, KMP doesn’t support pure Swift libraries directly. This realisation led me to an extensive search for workarounds.
I toyed with various approaches:
- Swift-Kotlin Interop: I attempted to use a Swift-Kotlin wrapper to bridge the gap, only to find that it wouldn’t support the pure Swift Amplify library.
- Firebase as a Frontend: Considering Firebase Auth as an alternative, which would entail a substantial rewrite of our backend—a daunting task.
- KMP Cognito IDP Library: Found a promising library only to discover it was outdated and potentially abandoned.
After numerous dead ends and much frustration, I resorted to re-reading the documentation, hoping for a spark of inspiration.
A (not so) elegant solution
Finally, I concocted a rather “icky” solution. By leveraging global variables, I made the iOS app set the authentication token, which the common code could then access. It’s not pretty, and it’s definitely not something I’d want to showcase, but it worked.
This temporary fix involved setting a global value and using a listener in the iOS app to update it upon login. This way, the common code could access the token when needed. Not elegant, but functional.
Conclusions and future directions
KMP is tantalisingly close to being a game-changer. The ecosystem is growing, and the ability to write shared code for iOS and Android is a huge plus. However, until KMP supports pure Swift libraries or there’s a significant improvement in interoperability, it remains a challenge for complex, real-world applications.
The hardest part of setting up KMP is managing the dependencies and ensuring compatibility with native libraries is quite challenging. The setup involves navigating a lot of moving parts, from Kotlin to Swift to Objective-C. You need to define expected functions in common code and implement them for each platform, which can be overwhelming.
KMP allows using native views and accessing native APIs directly, which can provide a more native feel compared to Flutter’s widget-based approach. However, Flutter’s consistent experience across platforms is still a significant advantage. With KMP, you can use Multiplatform Compose, which translates to SwiftUI or Jetpack Compose, enhancing the native feel.
For now, we’ll stick with Flutter and continue to explore plugin-based solutions for the heavy lifting. The future of KMP looks promising, and I’m hopeful that with ongoing improvements, it will soon become a viable option for more demanding projects.
Final thoughts
This journey was a mix of excitement, frustration, and discovery. While we’re not ready to switch to Kotlin Multiplatform just yet, the experience has broadened our understanding and opened new possibilities for future projects. If you’re considering KMP, be prepared for some yak shaving, but know that it’s an adventure worth taking.