Upgrade to Pro — share decks privately, control downloads, hide ads and more …

KMPTeam_YenaHwang_DroidKaigi2025_Compose_Multip...

Avatar for yena-hwang yena-hwang
September 17, 2025
210

 KMPTeam_YenaHwang_DroidKaigi2025_Compose_MultiplatformとSwiftUIで作るハイブリッドモバイルアプリ.pdf

DroidKaigi 2025 にて発表したセッション
「Compose MultiplatformとSwiftUIで作るハイブリッドモバイルアプリ:コード共有とUI融合の実践」 の資料です。

Kotlin MultiplatformとCompose Multiplatformを用いて、SwiftUIとのUI統合やビジネスロジックの共通化をどのように実現したのかを、実際のプロジェクト事例を紹介しています。

And!
We're hosting a DroidKaigi2025 After Party!
Date: October 9  19:00~21:00
Location: KINTO Technologies Office (TOKYO JCT), 16th floor of the office tower at COREDO Muromachi 2
室町古河三井ビルディング(COREDO室町2)
2-3-1 Nihonbashi Muromachi, Chuo City, Tokyo

Avatar for yena-hwang

yena-hwang

September 17, 2025
Tweet

Transcript

  1. From Android to KMP-Evolution Our team started with Android development,

    and now we focus on Kotlin Multiplatform to deliver cross-platform experiences. Members Yao Xie – Android / Compose Multiplatform Yonghui Chen – Android / iOS / Kotlin Multiplatform Garamoi Choi– Android / Kotlin Multiplatform / API @hemoptysisheart KMP Team
  2. Scan QR Code & Ask your questions here! Slido code

    #67258131 https://app.sli.do/event/455CaD4m pV23uyVgNjT2CZ
  3. Context Last year, we began a new product with our

    existing code - Jetpack x SwiftUI.From the start, the prototype had to be: • High Speed: very short timeline • Low Cost: small dev team • High Quality: UI performance equal to native apps High Quality Low Cost High Speed
  4. Context But as you know, “High Speed, Low Cost, and

    High Quality” often feels like an impossible triangle — you usually only get two. That was the challenge we faced. High Quality Low Cost High Speed Slow High Cost X IMPOSSIBLE Low Quality
  5. KMP + CMP We saw an opportunity to go a

    step further – share both logic & UI layer across platforms. The solution?
  6. This approach promised a rare mix: • Ship a prototype

    quickly with a small team • Native-level performance • Reuse Jetpack Compose components • Shared code for logic and UI • Higher efficiency to meet the deadline It looked like a practical way to break the “impossible triangle”.
  7. KMP: Business logic, API serviceand data management CMP: UI screens

    of lists / cards / forms, data-heavy details Native: Navigation / gestures, Map / Camera / Wallet, strong platform styling Quick heuristics A pragmatic blueprint for building hybrid mobile apps with CMP
  8. BEST OF BOTH WORLDS: • Platform-specific UI/UX guidelines • Native

    component integration (Maps, Camera) • Gradual migration path • Team expertise utilization USE CASES: • Existing native apps • Platform-specific design requirements • Complex native integrations Why Hybrid Architecture?
  9. Project Structure my-cmp-app/ ├── composeApp/ │ ├── src/ │ │

    ├── commonMain/ // CMP Shared code │ │ ├── androidMain/ // Android-specific │ │ └── iosMain/ // iOS-specific ├── iosApp/ │ ├── Views/ // SwiftUI views │ ├── Screens/ // Native screens │ └── ComposeViewContainer.swift └── shared/ // KMP domain layer ├── viewmodels/ └── models/
  10. End-to-End Blueprint • Module layout for clean separation between shared

    and platform-specific code • Shared ViewModel contracts to decouple logic from UI • Bidirectional UI interop: • Embed CMP views in Native screens • Embed Native components inside CMP screens • Navigation & state management strategies that work across platforms
  11. This hybrid structure allows seamless tab switching and demonstrates how

    shared and native UI components can coexist. MainScreen uses a bottom navigation bar with four tabs: Tab UI Implementation Application CMP Lineup CMP HelpCenter CMP Settings Native (SwiftUI on iOS) Demo
  12. Migrating from Native Navigation to CMP-based Hybrid Navigation • Refactor

    existing navigation stacks to route between native & CMP • Abstract platform-specific navigation logic behind shared interfaces
  13. DUPLICATE BUSINESS LOGIC ACROSS PLATFORMS For validation (e.g. email, phone,

    postal code, password strength, date formats), we needed implement multiple validators.
  14. TOTAL 24 x2! If implemented separately: Android: 24 validators in

    Kotlin iOS: 24 validators in Swift → 48 implementations total → 48 ValidationResults total → plus 48 sets of unit tests
  15. The KMP solution Move all validation logic into the shared

    KMP module. Implement each validator once in Kotlin. Expose as common functions/classes that can be called from: • CMP screens • Android/iOS Native screens
  16. DECISION MATRIX: CMP vs Native CRITERIA COMPOSE UI NATIVE UI

    Complex Lists Platform UX Map Integration Custom Animations Development Speed Team Expertise
  17. Difference between CMP & Flutter OVERLAY 🥲 INLINE RENDERING Fast

    and efficient CMP nesting Native vs Flutter nesting Native
  18. Difference between Flutter & CMP Host UI → Embedded UI

    Rendering path Performance impact Android: AndroidView inside Compose (same View system). iOS: CMP Skia surface hosts a UIKit view via UIKitView. Very Low (Android) / Low– Moderate (iOS) Android: ComposeView in a ViewGroup (Compose runs on platform renderer). iOS: SwiftUI/UIViewController hosts ComposeUIViewController (Skia surface inside). Low (Android) / Moderate (iOS) Flutter renders via Skia/Impeller; native view injected as PlatformView (texture/layer composition). Moderate; visible stutter on heavy views (Map, WebView). Native Activity/VC hosts Flutter engine surface. Extra startup cost (engine warm- up), stable after warm-up
  19. The Merits of CMP CMP Use the native MapView as-is,

    and render icons/routes with the native API. Moves smoothly with no performance issues. • Place native components such as MKMapView directly • Can be replaced on a per- component basis • Maintain native performance and accessibility iOS Native Compose Host UI
  20. Complex Hybrid UI: Performance Comparison Framework Startup Time Memory Usage

    UI Smoothness Native CMP + Native Flutter+ Native
  21. HTTP/TLS/redirec ts/cookies Symptom/Cause: Engines differ; cookie persistence, redirects, TLS pinning

    vary by OS. Fix: Shared config for timeouts/cache/logging; inject per-platform engine+security policy via DI or expect/actual.
  22. Regex differences Symptom/Cause: JVM uses java.util.regex, iOS/Native uses a different

    engine (ICU). Features like \R, variable-width lookbehind, some Unicode classes behave differently or are unsupported on iOS. Fix: Avoid “spicy” features; rewrite into simpler sub-patterns; add a small adapter so you can swap engines later if needed.
  23. Time zones & DST Symptom/Cause: Time zone databases and formatting

    rules differ across platforms. Fix: Do all calculations in kotlinx-datetime; keep formatting as a platform concern via expect/actual.
  24. Fonts & typography (CJK/emoji) Symptom/Cause: Platform fallback differs → line

    height, truncation, emoji width vary. Fix: Bundle fonts, declare families/weights explicitly, set lineHeight/letterSpacing explicitly.
  25. Truncation/measurement differences Symptom/Cause: iOS/Skiko text layout isn’t bit-identical to Android.

    Fix: Use maxLines + TextOverflow.Ellipsis; avoid “exact fit” assumptions; do screenshot regression on key screens.
  26. Scroll & gesture physics Symptom/Cause: iOS inertia is “slipperier”, nested

    scroll feels different. Caution: Abstract scroll physics knobs and branch by platform, simplify containers on complex nested scroll pages.
  27. Practices: CMP/KMP lets us flexibly shift between shared and native

    code—maximizing reuse in prototypes, then moving toward native as products mature. CMP/KMP
  28. Fully leverage CMP flexibility Start Stage (≈99% shared) Goal: ship

    fast, validate ideas with minimal resources. Limited Dev Resources
  29. Fully leverage CMP flexibility Growth Stage (≈80% shared) Goal: scale

    product while enhancing native UX where it matters. Standard dev resources
  30. Fully leverage CMP flexibility Maturity Stage (≈50% shared) Goal: optimize

    performance, long- term maintainability, and team specialization. Abundant dev resources
  31. Gradual Adoption: For Mature Products Start Small 1% Safest entry

    point: introduce KMP/CMP in the smallest, low-risk areas.
  32. Gradual Adoption: For Mature Products Start Small 1% Safest entry

    point: introduce KMP/CMP in the smallest, low-risk areas. Stepwise Expansion 20% Expand adoption while ensuring stability and confidence.
  33. Gradual Adoption: For Mature Products Start Small 1% Safest entry

    point: introduce KMP/CMP in the smallest, low-risk areas. Stepwise Expansion 20% Expand adoption while ensuring stability and confidence. End Stage e.g. 50% Reach a sustainable mix of shared and native code.