← All articles
black flat screen computer monitor

Cross-Platform Mobile Development Tools

Languages 2026-02-09 · 6 min read mobile react-native flutter expo capacitor cross-platform

Cross-Platform Mobile Development Tools

Photo by Muhammad Rosyid Izzulkhaq on Unsplash

Building separate iOS and Android apps doubles your engineering effort. Cross-platform tools let you write once and deploy to both -- but they all make tradeoffs. Some sacrifice native feel for development speed. Others sacrifice simplicity for pixel-perfect control. This guide compares the real options in 2026 and helps you pick the right one.

React Native cross-platform mobile development logo

React Native

React Native renders native UI components using JavaScript and React. Your code runs in a JavaScript engine, but the buttons, text inputs, and scroll views are the actual native platform widgets.

Setup with the React Native CLI

# Create a new project
npx @react-native-community/cli init MyApp
cd MyApp

# Run on iOS (macOS only)
npx react-native run-ios

# Run on Android
npx react-native run-android

Example Component

import React, { useState, useEffect } from "react";
import { View, Text, FlatList, StyleSheet, ActivityIndicator } from "react-native";

interface User {
  id: string;
  name: string;
  email: string;
}

export function UserList() {
  const [users, setUsers] = useState<User[]>([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch("https://api.example.com/users")
      .then((res) => res.json())
      .then((data) => {
        setUsers(data);
        setLoading(false);
      });
  }, []);

  if (loading) return <ActivityIndicator size="large" />;

  return (
    <FlatList
      data={users}
      keyExtractor={(item) => item.id}
      renderItem={({ item }) => (
        <View style={styles.row}>
          <Text style={styles.name}>{item.name}</Text>
          <Text style={styles.email}>{item.email}</Text>
        </View>
      )}
    />
  );
}

const styles = StyleSheet.create({
  row: { padding: 16, borderBottomWidth: 1, borderBottomColor: "#eee" },
  name: { fontSize: 16, fontWeight: "bold" },
  email: { fontSize: 14, color: "#666" },
});

New Architecture

React Native's New Architecture (Fabric renderer + TurboModules) is now the default. Key improvements:

Strengths: Huge ecosystem (npm packages), hot reloading, React knowledge transfers directly, strong community, most third-party SDKs have React Native support.

Weaknesses: Native module complexity (bridging to platform APIs requires Objective-C/Swift or Java/Kotlin), debugging across JS and native layers is harder than pure native, some platform-specific UI behavior requires platform-specific code.

Expo

Expo is a platform built on top of React Native that eliminates most of the native toolchain complexity. You don't need Xcode or Android Studio for most development work.

Setup

# Create a new Expo project
npx create-expo-app MyApp
cd MyApp

# Start development
npx expo start

# Scan the QR code with Expo Go app on your phone
# Or press 'i' for iOS simulator / 'a' for Android emulator

Expo Router (File-Based Routing)

app/
  _layout.tsx        # root layout
  index.tsx          # home screen
  settings.tsx       # settings screen
  users/
    [id].tsx         # dynamic route: /users/123
    _layout.tsx      # nested layout for users section
// app/users/[id].tsx
import { useLocalSearchParams } from "expo-router";
import { View, Text } from "react-native";

export default function UserDetail() {
  const { id } = useLocalSearchParams();
  return (
    <View>
      <Text>User ID: {id}</Text>
    </View>
  );
}

EAS Build and Submit

Expo Application Services (EAS) handles building and submitting to app stores:

# Install EAS CLI
npm install -g eas-cli

# Configure builds
eas build:configure

# Build for iOS
eas build --platform ios

# Build for Android
eas build --platform android

# Submit to App Store / Play Store
eas submit --platform ios
eas submit --platform android

Development Builds (Custom Native Code)

When you need native modules not included in Expo Go:

# Create a development build
npx expo install expo-dev-client
eas build --profile development --platform ios

# Install the development build on your device
# Then use expo start --dev-client

Strengths: Dramatically simpler setup (no Xcode/Android Studio for most work), over-the-air updates, EAS Build handles native compilation in the cloud, file-based routing with Expo Router, growing library of pre-built native modules.

Weaknesses: Some native modules aren't available in Expo Go (need a development build), EAS Build has usage limits on the free tier, slightly less control than bare React Native.

Recommendation: Use Expo for new React Native projects unless you have a specific reason not to. The development experience is significantly better, and you can always eject to bare React Native if needed.

Flutter

Flutter uses Dart and its own rendering engine -- it doesn't use native UI components. Instead, it draws every pixel using Skia (now Impeller), giving you complete control over appearance but a different feel from native apps.

Setup

# Install Flutter (see flutter.dev for platform-specific instructions)
flutter doctor  # check your environment

# Create a new project
flutter create my_app
cd my_app

# Run
flutter run

Example Widget

import 'package:flutter/material.dart';

class UserList extends StatefulWidget {
  @override
  _UserListState createState() => _UserListState();
}

class _UserListState extends State<UserList> {
  List<Map<String, dynamic>> users = [];
  bool loading = true;

  @override
  void initState() {
    super.initState();
    loadUsers();
  }

  Future<void> loadUsers() async {
    final response = await http.get(Uri.parse('https://api.example.com/users'));
    setState(() {
      users = jsonDecode(response.body);
      loading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (loading) return Center(child: CircularProgressIndicator());

    return ListView.builder(
      itemCount: users.length,
      itemBuilder: (context, index) {
        return ListTile(
          title: Text(users[index]['name']),
          subtitle: Text(users[index]['email']),
        );
      },
    );
  }
}

Hot Reload

Flutter's hot reload is its killer feature. Changes appear in under a second without losing app state. It's faster than React Native's equivalent and makes UI iteration extremely fast.

Strengths: Fastest hot reload, consistent UI across platforms (pixel-perfect control), excellent performance (compiled to native ARM code), strong widget library, good for custom/branded UI that shouldn't look "native".

Weaknesses: Dart is a niche language (smaller talent pool), Flutter apps don't look native by default (Material or Cupertino widgets), the ecosystem is smaller than React Native's, third-party SDK support can lag (some vendors don't provide Flutter packages).

Capacitor (Web-Based)

Capacitor (by the Ionic team) wraps a web app in a native container. Your app runs in a WebView, and Capacitor provides JavaScript APIs to access native features (camera, filesystem, push notifications).

# Add Capacitor to an existing web project
npm install @capacitor/core @capacitor/cli
npx cap init

# Add platforms
npx cap add ios
npx cap add android

# Sync web assets to native projects
npx cap sync

# Open in native IDE
npx cap open ios      # opens Xcode
npx cap open android  # opens Android Studio
// Access native APIs from your web code
import { Camera, CameraResultType } from "@capacitor/camera";

const photo = await Camera.getPhoto({
  resultType: CameraResultType.Uri,
  source: CameraSource.Camera,
  quality: 90,
});

Strengths: Use any web framework (React, Vue, Svelte, Angular), reuse your existing web codebase, web developers become mobile developers immediately, plugins for native APIs.

Weaknesses: Performance is limited by the WebView (not suitable for graphics-intensive apps), the app doesn't feel native (it's a web app in a container), some native features have limited support.

Best for: Teams that have an existing web app and want a mobile presence without learning a new framework. Content-heavy apps, internal tools, and MVPs where speed-to-market matters more than native feel.

Comparison

Feature React Native Expo Flutter Capacitor
Language JavaScript/TS JavaScript/TS Dart Any web tech
Rendering Native components Native components Custom engine WebView
Native Feel Good Good Customizable Web-like
Hot Reload Good Good Excellent Good
Native APIs Via modules Via Expo modules Via plugins Via plugins
Build Setup Complex Simple (EAS) Moderate Simple
Web Support react-native-web Expo for Web Flutter Web Native web
Team Skills React/JS React/JS Dart Web dev

Development Tools

Regardless of framework, you'll need these tools:

Simulators/Emulators: iOS Simulator (Xcode, macOS only) and Android Emulator (Android Studio). There's no avoiding these for testing.

Flipper: A debugging platform for React Native and native mobile apps. Inspect network requests, view component hierarchies, access device logs, and use custom plugins. (Note: Expo is moving toward its own DevTools.)

Reactotron: A desktop app for inspecting React Native apps -- state changes, API responses, benchmark timings, and error tracking.

Maestro: UI testing framework for mobile apps. Write tests in YAML that run on real devices and emulators:

# maestro/login-test.yaml
appId: com.myapp
---
- launchApp
- tapOn: "Email"
- inputText: "[email protected]"
- tapOn: "Password"
- inputText: "password123"
- tapOn: "Log In"
- assertVisible: "Welcome"
maestro test maestro/login-test.yaml

Recommendations