One codebase, two app stores. The promise is real — and so are the trade-offs in performance, native integration, and platform-feel.
← Back to Client Side| Framework | Language | UI strategy | Sweet spot |
|---|---|---|---|
| React Native | JS / TS | JS → native widgets | React teams; products that want platform-native feel. |
| Flutter | Dart | Skia/Impeller canvas — own widgets | Pixel-identical brand UI across platforms; great animations. |
| .NET MAUI | C# | Abstraction over native widgets | Microsoft shops; line-of-business apps. |
| Kotlin Multiplatform | Kotlin | Shared logic; native UI per platform | Native UI quality with shared business logic / networking / DB. |
| Ionic + Capacitor | JS / TS (web) | WebView wrapping a web app | Web teams shipping a "good enough" mobile app. |
| Expo (RN) | JS / TS | RN with managed tooling | Most new RN projects start here. |
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.
UIView / android.View, not a canvas.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.
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.
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.
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.
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).
FlashList) and Flutter both ship 60+ fps; WebView typically can't.Reanimated on the UI thread.React Native (Expo). The mental model and ecosystem carry over.
Flutter. Same pixels on every device.
Kotlin Multiplatform — share logic, write SwiftUI / Compose.
Ionic + Capacitor (or wrap a PWA). Accept the WebView feel.
.NET MAUI. C# everywhere from API to phone.
Don't go cross-platform. Just write native.