Seamless KMP on iOS: Enhancing the Experience with SKIE
Kotlin Multiplatform (KMP) is a game-changer for sharing business logic across platforms. However, for iOS developers consuming this shared code, the experience can sometimes feel foreign. This is because KMP compiles to iOS via Objective-C interoperability, which doesn’t natively support some of modern Kotlin’s (and Swift’s) best features.
This is where SKIE (Swift Kotlin Interface Enhancer), developed and maintained by Touchlab, comes in.
It is worth noting that JetBrains is working on swift-export to natively improve the iOS developer experience. However, until that feature is ready, tools like SKIE are the best way to bridge the gap.
The “Vanilla” KMP Experience on iOS
When you compile Kotlin to an iOS framework without tools like SKIE, you might encounter several friction points:
- Sealed Classes: In Kotlin,
sealed classesallow for exhaustivewhenstatements. In Objective-C (and thus Swift via KMP), these become standard class hierarchies. You lose the compiler’s ability to ensure you’ve handled all cases in aswitchstatement. - Enums: Similar to sealed classes, Kotlin enums don’t always map 1-to-1 to Swift enums with the same power and flexibility.
- Coroutines: Kotlin’s
suspendfunctions are generated as functions with completion handlers (callbacks) in Objective-C. While Swift hasasync/await, bridging these callbacks manually is tedious and error-prone. - Flows: Kotlin
Flowis a powerful stream processing tool. In standard KMP, it appears as a generic object, requiring adapters to be consumed comfortably in Swift.
How SKIE Improves the iOS Developer Experience
SKIE acts as a bridge that generates Swift-friendly code on top of the Objective-C header. It doesn’t change the Kotlin compiler; it enhances the output.
1. Exhaustive Sealed Classes & Enums
SKIE generates real Swift enums for your Kotlin sealed classes and interfaces. This means you can use Swift’s switch statement with full exhaustiveness checking.
| |
Without SKIE, you would have to cast types or check is types, often needing a default case that swallows future errors.
2. Native Async/Await Support
SKIE automatically converts Kotlin suspend functions into Swift async throws functions. This allows iOS developers to use the modern concurrency model they are used to.
| |
3. Flows as AsyncSequences
Perhaps one of the coolest features is transforming Kotlin Flow into Swift AsyncSequence. This allows you to iterate over data streams using a simple for await loop.
| |
How to Configure SKIE
Setting up SKIE is incredibly straightforward. It is distributed as a Gradle plugin.
- Open your root
build.gradle.ktsor thebuild.gradle.ktsof your shared module. - Add the SKIE plugin to the
pluginsblock:
| |
- Sync your Gradle project.
That’s it! SKIE will automatically hook into the link task of your iOS framework and generate the enhanced Swift code.
For more advanced configuration, such as disabling specific features or fine-tuning enum generation, you can use the skie configuration block:
| |
Conclusion
If you are building a KMP project that targets iOS, using SKIE is almost mandatory for a polished experience. It respects the platform differences while allowing you to share the maximum amount of logic, keeping your iOS team happy and your codebase clean.
