Skip to content
All posts
July 27, 20264 min read

Kotlin Multiplatform Mobile: Sharing Code Between Android and iOS

KMP lets you share business logic between Android and iOS while keeping native UI on each. Here's what's actually worth sharing, what to leave native, and the realistic trade-offs from shipping it.

Kotlin MultiplatformKMPAndroidiOSCross-Platform
Share:

Kotlin Multiplatform promises something cross-platform frameworks usually don't: share your logic without giving up native UI. You write your data, networking, and business rules once in Kotlin, and each platform keeps its own native interface. After using it on real projects, I think that promise mostly holds — but only if you're disciplined about where the line between shared and native sits.

Share Logic, Not UI (Usually)

The sweet spot for KMP is the layer beneath the UI: models, networking, persistence, validation, and business rules. That code is identical on both platforms and benefits most from being written once. The UI, by contrast, is where platforms genuinely differ, and forcing a shared UI is often where cross-platform projects get into trouble. My default is shared logic with native UI — Compose on Android, SwiftUI on iOS — so each platform feels native while the rules behind it stay in one place. Compose Multiplatform can share UI too, and it's maturing, but I treat shared UI as an opt-in for specific screens, not the default.

Structure Around commonMain

A KMP module organizes code by source set.

code
commonMain
holds the shared, platform-agnostic Kotlin. Platform-specific implementations live in
code
androidMain
and
code
iosMain
, and the
code
expect
/
code
actual
mechanism bridges them when shared code needs something platform-specific.

kotlin
// commonMain
expect fun platformName(): String

// androidMain
actual fun platformName() = "Android"

// iosMain
actual fun platformName() = "iOS"

Most of your code should sit in

code
commonMain
and never need
code
expect
/
code
actual
; the bridge is for the few genuinely platform-bound things like secure storage or system APIs.

Pick Multiplatform Libraries

The ecosystem matters. For networking I use Ktor rather than Retrofit, because Ktor runs on all KMP targets. For serialization, kotlinx.serialization. For concurrency, coroutines and Flow work across platforms. Choosing libraries that already support multiplatform keeps your

code
commonMain
truly common; pulling in an Android-only library forces logic out of the shared layer and defeats the point. This constraint actually steers you toward clean, dependency-light code, which is no bad thing.

The iOS Side Has Real Friction

Honesty matters here: KMP is smoother on Android than iOS, because Android is Kotlin's home turf. On iOS, your shared module is consumed as a framework, and there are rough edges — interop with Swift, debugging across the boundary, and a build setup that's less plug-and-play than the Android side. It's gotten much better, but an iOS developer touching the shared code will feel the seams more than the Android one. Budget for that learning curve rather than assuming it's free.

Is It Worth It?

The calculus depends on how much logic you actually share and whether you're committed to both platforms. If your app is mostly UI with thin logic, KMP's overhead may exceed its savings — there's just not much to share. If it has substantial business logic, networking, and rules that must behave identically on both platforms, sharing that once and guaranteeing consistency is a real win, and it eliminates the bugs that come from two implementations drifting apart. For a solo developer shipping to both stores, the consistency guarantee — fix a bug once, it's fixed everywhere — is often the deciding benefit, more than the raw lines-of-code saved.

A practical way to decide whether KMP fits is to estimate, honestly, how much of your app is logic versus UI. Sketch the layers — networking, models, persistence, business rules on one side; screens, navigation, platform interactions on the other — and look at where the weight sits. If the logic side is substantial and must behave identically on both platforms, KMP turns that into a single tested implementation and eliminates a whole class of drift bugs. If the app is thin glue over native UI with little shared logic, the setup cost and iOS friction probably outweigh the savings. KMP isn't a religion to adopt wholesale; it's a tool that pays off in proportion to how much genuine logic you have to share, so let that proportion make the call.

Key Takeaways

  • KMP's sweet spot is sharing logic — models, networking, persistence, rules — while keeping native UI on each platform.
  • Put most code in
    code
    commonMain
    ; use
    code
    expect
    /
    code
    actual
    only for the few genuinely platform-bound pieces.
  • Choose multiplatform libraries like Ktor and kotlinx.serialization so your shared layer stays truly common.
  • Expect more friction on the iOS side than Android; budget for the framework interop and build learning curve.
  • KMP pays off when there's substantial shared logic and you want a single source of truth across both stores; it's overhead for UI-heavy, logic-light apps.
Share:
S

Sudarshan Chaudhari

AI Systems Builder / Product Engineer

Bangkok, Thailand

Solo Android developer with 13+ years in QA, building Android apps, AI automation systems, and developer tools at SudarshanTechLabs.

Stay updated

Get new posts on Android, Kotlin, and solo dev straight to your inbox.

Newsletter preferences

Related Apps

MyFamilyTracker

Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.

Building something? Available for Android dev and QA consulting.

Work with me

Comments — powered by Giscus

Apps tagged with this