Client Platforms · 3 of 6

Mobile (Cross-platform)

One codebase, two app stores. The promise is real — and so are the trade-offs in performance, native integration, and platform-feel.

React NativeFlutter.NET MAUIKotlin MultiplatformIonic / Capacitor
← Back to Client Side
Quick Facts

At a Glance

Basic Concepts

  • Cross-platform = one codebase that compiles or runs on iOS and Android (often web/desktop too).
  • Three architectural approaches: JS bridge → native widgets (RN), own renderer over a canvas (Flutter), shared logic + native UI (KMP).
  • You still need a Mac and Xcode to ship the iOS build — no framework escapes Apple's tooling.
  • Most apps end up writing some native code for camera, push, payments, deep links, widgets.
  • App-store review applies the same rules — frameworks don't get you a faster path.
Landscape

The Major Options

FrameworkLanguageUI strategySweet spot
React NativeJS / TSJS → native widgetsReact teams; products that want platform-native feel.
FlutterDartSkia/Impeller canvas — own widgetsPixel-identical brand UI across platforms; great animations.
.NET MAUIC#Abstraction over native widgetsMicrosoft shops; line-of-business apps.
Kotlin MultiplatformKotlinShared logic; native UI per platformNative UI quality with shared business logic / networking / DB.
Ionic + CapacitorJS / TS (web)WebView wrapping a web appWeb teams shipping a "good enough" mobile app.
Expo (RN)JS / TSRN with managed toolingMost new RN projects start here.
Mechanics

How They Actually Work

React Native — Native widgets, JS logic

JS executes in JSC (or Hermes) on a separate thread. The new Fabric renderer + JSI (JavaScript Interface) replaced the old async bridge — synchronous calls into native, no more JSON serialization on every frame. Result: scroll perf and gesture handling close to native.

  • UI is real UIView / android.View, not a canvas.
  • Hot reload & OTA updates (CodePush, EAS Update) — ship JS changes without store review.
  • Expo is now the recommended way in.
Flutter — Own renderer, Dart everywhere

Dart compiles AOT to native ARM. Flutter draws every pixel itself via Skia / Impeller — your Button isn't a UIButton, it's a Flutter widget that looks like one. Pros: identical UI across OS/version, great animations. Cons: accessibility & platform conventions need explicit work; binary size baseline is larger.

  • Hot reload is famously fast.
  • Ships to iOS, Android, web, macOS, Windows, Linux, embedded — one codebase.
Kotlin Multiplatform — Share logic, not UI

Different philosophy: share networking, models, business logic, persistence in Kotlin; write the UI natively (SwiftUI on iOS, Compose on Android). Compose Multiplatform (JetBrains) is bringing shared UI as an option, but the value prop is "native UI without parallel logic codebases."

Used in production by Netflix, Cash App, Philips, JetBrains.

.NET MAUI — Successor to Xamarin

C# / XAML, abstracts native controls per platform. Same C# you write for the backend. Targets iOS, Android, macOS (Catalyst), Windows. Most popular inside Microsoft-stack enterprises.

Ionic + Capacitor — The WebView Approach

A web app rendered in a WKWebView / Android WebView, with a JS bridge for native APIs (camera, geolocation, etc.). Capacitor replaced the older Cordova. Cheapest path if you already have a web app — but the gestures, scroll feel, and keyboard handling never quite reach native.

The "Native Module" Reality

Every cross-platform app eventually needs a native module — for the camera library that doesn't have a JS wrapper, for the audio session, for the in-app purchase quirk. Plan for this: pick a framework whose native bridge you'd actually want to write in (Swift / Kotlin / Objective-C / Java).

Performance Trade-offs
  • Startup: Flutter and KMP cold-start close to native; RN is improving with Hermes; WebView-based apps are the slowest.
  • Scrolling huge lists: RN (with FlashList) and Flutter both ship 60+ fps; WebView typically can't.
  • Heavy animations: Flutter's strength. RN has Reanimated on the UI thread.
  • Binary size: RN ~10–15 MB minimum, Flutter ~20+ MB minimum, KMP near-native.
Picking

Choosing a Framework

Web team going mobile

React Native (Expo). The mental model and ecosystem carry over.

Brand-driven UI everywhere

Flutter. Same pixels on every device.

Native UI is non-negotiable

Kotlin Multiplatform — share logic, write SwiftUI / Compose.

Existing web app, minimal budget

Ionic + Capacitor (or wrap a PWA). Accept the WebView feel.

Microsoft stack shop

.NET MAUI. C# everywhere from API to phone.

Single-platform launch

Don't go cross-platform. Just write native.

Pitfalls

Common Anti-Patterns

  • Assuming "write once, run everywhere" — you'll still have iOS-only and Android-only branches in your code.
  • Ignoring platform UI guidelines — back gestures, share sheets, system fonts, status bar handling differ.
  • OTA-updating native code — Apple's review rules forbid runtime-shipping new features as JS.
  • Skipping native engineers — you'll need at least one who can debug Xcode build errors and write a native module.
  • Binary bloat from over-eager dependencies — every npm package shows up in app size.
Continue

Other Client Platforms