cloudparts

Cross-platform mobile apps

Write an Android and iOS app mostly once: a framework runs shared code on both platforms and either drives the native UI controls, draws every pixel itself, shows web pages in a native shell, or shares only the logic under native screens.

4 technologies on this page ↓

How it works

A native app is written twice: Kotlin against the Android SDK and Swift against Apple’s frameworks, each built in its own IDE and shipped through its own store. Cross-platform frameworks share code between the two, and differ in what they share and how the interface reaches the screen. React Native runs JavaScript in an engine embedded in the app and turns React components into real platform views. Its original design passed every call across an asynchronous bridge that serialized the data, which became a bottleneck for frequent updates; the New Architecture, on by default since React Native 0.76, lets JavaScript and native code call each other synchronously through JSI, with a renderer and native module system rewritten in C++. Flutter takes the opposite route: it implements every control itself in Dart, paints them with its own engine (Impeller) shipped inside the app, and compiles to ARM machine code for release. Apache Cordova and Capacitor wrap a web app’s HTML, CSS and JavaScript in the system WebView inside a native shell, with plugins for device features. Kotlin Multiplatform shares business logic written in Kotlin and leaves the screens native, or shares them too with Compose Multiplatform. Whatever the approach, each platform still gets its own signed binary that goes through store review, and native features the framework lacks are added as modules or plugins written in Swift, Kotlin or Java. Some frameworks can also replace the JavaScript and assets of an installed app over the air, but never its native code.

Think of it as

A touring play. React Native sends one script to each country, where local actors perform it on the local stage. Flutter brings its own cast and set everywhere, so every show looks the same. A WebView app projects a recording of the play onto the local stage. Kotlin Multiplatform shares the script, and each country stages it its own way.

Reach for it when

  • One team must ship the same app on Android and iOS, and most screens are forms, lists and content
  • A web team moving to mobile: React Native and Capacitor reuse JavaScript, React and web skills
  • A branded interface that must look identical on every platform and OS version: a framework that draws its own widgets
  • Existing native apps that want to stop writing the same logic twice: share it with Kotlin Multiplatform and keep the native screens

Think twice when

  • The product works as a website: a progressive web app gets offline support, push notifications and a home-screen icon without a native container
  • The app depends on each new OS release’s features from day one: the framework has to adopt them first, as Expo SDK 58 did for the scene-based life cycle that apps built with the iOS 27 SDK need
  • A WebView wrapper where users expect a native feel: Facebook built React Native because WebViews couldn’t deliver a truly native experience

A real example

A grocery delivery startup has three React developers and needs Android and iOS apps. They build one React Native app with Expo: product lists, the basket, checkout and order tracking are shared code, and both apps use the platforms’ own controls. Their payment provider only ships Swift and Kotlin SDKs, so they add its native module and rebuild both binaries. When a rounding bug shows wrong basket totals, the fix is a JavaScript change that reaches installed apps on their next launch without store review; upgrading the payment SDK later is a native change and goes through the stores. A bank with separate Android and iOS teams takes the other route: it moves validation, sync and pricing rules into a Kotlin Multiplatform module and keeps its existing SwiftUI and Jetpack Compose screens.

Technologies

Specific products, and what each does differently.

Also used for cross-platform mobile apps

Products of other kinds that are often used this way, grouped by what they are.

Four ways to share code#

The approaches differ mainly in who draws the interface.

Native views from JavaScriptOwn rendererWebView in a native shellShared logic, native UI
ExamplesReact Native, ExpoFlutterApache Cordova, CapacitorKotlin Multiplatform
LanguageJavaScript or TypeScript with ReactDartHTML, CSS and JavaScriptKotlin for shared code; Swift and Kotlin for screens
What draws the screenThe platform’s own views, created from React componentsThe framework’s own widgets, painted by an engine shipped in the appThe system WebView, inside a native wrapperEach platform’s own UI toolkit, or Compose Multiplatform for shared screens
Trade-offLooks native; JavaScript and native code meet at a boundary, an asynchronous bridge before the New ArchitectureLooks the same on every OS version, but the platform’s look is re-implemented rather than usedReuses a web app, but doesn’t feel like a native appEasy to add to existing native apps; screens are still written per platform unless you adopt Compose Multiplatform
  • All four still produce one signed binary per platform that goes through App Store and Google Play review.

Often confused with

Where it came from2008–2025

The first popular answer reused the web. PhoneGap, created in 2008, let developers build apps for several platforms from one web codebase. Apache Cordova, the open-source project behind it, runs the app’s HTML, CSS and JavaScript in a WebView inside a native wrapper, and Capacitor, which calls itself the next evolution of hybrid apps, later took the same approach.

In March 2015 Facebook open-sourced React Native for iOS, with Android to follow. Its engineers wrote that WebViews offered flexibility but couldn’t deliver a truly native user experience, so React Native ran React in an embedded JavaScript engine, off the main thread, and drove real platform views; the motto was “learn once, write anywhere”, not identical apps everywhere. Google took the other path with Flutter, whose first stable release, 1.0, shipped on 4 December 2018: it drew every pixel with its own engine and compiled Dart to native ARM code.

The field then narrowed. Adobe ended development of PhoneGap in August 2020, citing declining usage and pointing to progressive web apps among the alternatives. Microsoft ended Xamarin support on 1 May 2024 and moved Xamarin.Forms users to .NET MAUI. JetBrains declared Kotlin Multiplatform stable in November 2023 and Compose Multiplatform for iOS stable in May 2025. React Native made its New Architecture the default in October 2024, and its docs now recommend starting new apps with a framework such as Expo.

Why it’s built this way

Native controls instead of a WebView
Facebook wanted the flexibility of web development without giving up a native user experience, which WebViews couldn’t provide, so React Native maps React components to real platform views.
Draw every pixel
Flutter implements each control in Dart instead of calling the platform’s, which its docs say gives unlimited extensibility, avoids a bottleneck from switching between Flutter and platform code, and makes an app look the same on every OS version.
Share the logic, keep the UI native
Kotlin Multiplatform lets teams reuse as much code as they want and write native code where needed, so it can be added to an existing app gradually and at low risk.
Synchronous calls instead of a bridge
Serializing every call across React Native’s asynchronous bridge became a bottleneck that made 60 frames per second hard to reach, so the New Architecture lets JavaScript and native code call each other directly through JSI.

Timeline

  1. 2008

    PhoneGap is created to build mobile apps from web code

  2. 2015

    Facebook open-sources React Native for iOS

  3. 2018

    Google releases Flutter 1.0

  4. 2020

    Adobe ends development of PhoneGap and PhoneGap Build

  5. 2023

    Kotlin Multiplatform becomes stable

  6. 2024

    Xamarin support ends in May; React Native turns on its New Architecture by default in October

  7. 2025

    Compose Multiplatform for iOS becomes stable

Sources14

Improve this page on GitHub