RO EN

Mobile applications in 2026: native, Flutter, React Native, .NET MAUI or PWA?

Mobile applications in 2026: native, Flutter, React Native, .NET MAUI or PWA? ✨ Imagine generată cu AI
Doru Bulubașa
02 November 2026
29 views

Sales agents of a distribution company work all day in the field. They take orders from stores, scan barcodes, take pictures of shelves, and send everything to headquarters. Until now, they used a web application on their phone, which froze exactly in stores without signal. The commercial director has a solution: “We’ll make a mobile app. And I want it to be in the App Store to look serious.”

The team has three options on the table. Two native apps, one for iOS and one for Android, written by different people. A cross-platform app, with Flutter, React Native, or .NET MAUI. Or a better web app, that is, a PWA. Each has convinced supporters, and each costs differently, not only at the start but every year the app remains in the stores.

This is the fourth article in the series about choosing UI technology. We went through web, native desktop in .NET, and desktop with web technologies. Now we move to the smallest and often most important screen: the phone.

Map: four paths to the phone

  • Native — Swift and SwiftUI for iOS, Kotlin and Jetpack Compose for Android. Two codebases, the best experience on each platform.
  • Cross-platform with own UI — Flutter draws every pixel itself, just like Avalonia on desktop. The same interface everywhere, fully controlled by the framework.
  • Cross-platform with native controls — React Native and .NET MAUI write code once but display the native controls of each platform. Compose Multiplatform and Kotlin Multiplatform occupy an intermediate position: the logic is always shared, and the UI can be shared or native.
  • Web — a PWA, that is, an installable web app, with an icon on the home screen, offline functionality, and, under certain conditions, push notifications.

As in previous articles, the same simple component shows a lot about the philosophy of each option. Here is a button that counts taps.

SwiftUI (native iOS)

struct Counter: View {
    @State private var count = 0

    var body: some View {
        Button("Taps: \(count)") { count += 1 }
    }
}

Jetpack Compose (native Android)

@Composable
fun Counter() {
    var count by remember { mutableIntStateOf(0) }
    Button(onClick = { count++ }) {
        Text("Taps: $count")
    }
}

Flutter

class Counter extends StatefulWidget {
  const Counter({super.key});

  @override
  State<Counter> createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int count = 0;

  @override
  Widget build(BuildContext context) => ElevatedButton(
        onPressed: () => setState(() => count++),
        child: Text('Taps: $count'),
      );
}

React Native

import { useState } from 'react';
import { Button } from 'react-native';

export function Counter() {
  const [count, setCount] = useState(0);
  return <Button title={`Taps: ${count}`} onPress={() => setCount(count + 1)} />;
}

.NET MAUI

public partial class CounterViewModel : ObservableObject
{
    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(Text))]
    private int count;

    public string Text => $"Taps: {Count}";

    [RelayCommand]
    private void Increment() => Count++;
}
<Button Text="{Binding Text}" Command="{Binding IncrementCommand}" />

SwiftUI and Jetpack Compose look strikingly similar because both adopted declarative UI. React Native is almost identical to React from the first article. Flutter requires a bit more ceremony code but is fully predictable. And MAUI uses exactly the same ViewModel with CommunityToolkit.Mvvm as WPF, Avalonia, and Uno from the desktop article.

Native: best result, highest cost

A native app has immediate access to any new operating system functionality, the best behavior for animations, gestures, and accessibility, and the shortest distance between official documentation and your code. When Apple or Google release a new API, the native app can use it from day one, without waiting for a plugin.

The price is duplication. Two codebases, two sets of tests, usually two people or two teams, and each feature is written and debugged twice. For a small company, this usually means one platform always lags behind.

It’s worth mentioning Kotlin Multiplatform: business logic, network access, and local database are written once in Kotlin and used both on Android and iOS. The interface can remain native on each platform. And if you want to share the interface as well, Compose Multiplatform has been stable on iOS since 2025. It’s a good path for teams that started with Android and want to reach iOS without a complete rewrite.

Choose native when: the app is the main product, user experience is a competitive advantage, you heavily use platform features (advanced camera, AR, widgets, watch integration), or you have the budget for two teams.

Flutter: one interface, drawn the same everywhere

Flutter uses the Dart language and its own rendering engine. On iOS and Android, the default engine is now Impeller. It does not use native controls but draws everything itself. The result is an identical interface on all devices, smooth animations, and very fast hot reload. It is probably the most productive development experience on the whole list.

Flutter has become one of the most used technologies for new apps, and the package ecosystem is large and mature. The community discussed a lot about Google’s investment level after the 2024 reorganizations, but the framework continued to receive regular releases.

The limits come precisely from its approach. The app will not automatically look like an iOS or Android app but like a Flutter app unless you consciously work on this aspect. Dart is a language the team probably needs to learn, although those coming from C# or Java adapt quickly. And any native functionality without an existing package must be written twice, in Swift and Kotlin, via a platform channel.

Choose Flutter when: you want a branded interface identical on iOS and Android, a small team that must deliver on both platforms quickly, or an app with rich UI and animations.

React Native: React on the phone, with native controls

React Native runs logic in JavaScript or TypeScript and displays native controls. For a team already working with React on the web, it’s the shortest path to mobile: the same concepts, the same hooks, often the same business logic, and even the same libraries.

In recent years, React Native completely changed its internal architecture. The new architecture, which eliminates the old asynchronous bridge between JavaScript and native code, became the default in version 0.76, and from version 0.82 it can no longer be disabled. For new projects, the React Native community and team recommend starting with Expo. Expo handles builds, native packages, and app updates, eliminating much of React Native’s historical pain points.

Limits: you depend on the quality of community libraries for native functionalities, and upgrading between major versions can sometimes be costly. Older apps stuck on the old architecture need a serious migration.

Choose React Native when: you already have a React team and want to share logic and people between web and mobile, or you want a native look on each platform with a single codebase.

.NET MAUI: C# on the phone, for .NET teams

.NET MAUI is the successor to Xamarin.Forms. One project, C# and XAML, native controls on Android, iOS, macOS, and Windows. For a .NET team, the argument is the same as for Blazor: the same language, the same libraries, the same DTOs, and the same dependency injection as in the backend.

MAUI also has an advantage the others don’t: Blazor Hybrid. With BlazorWebView, Razor components from the web app can run on the phone, natively, with access to camera, GPS, and files, just like in the desktop article. For a team that already has a SaaS in Blazor, this can mean a mobile app built largely from existing components.

Let’s be honest: MAUI has a mixed reputation. Many developers have reported stability issues, slower tooling, and a much smaller library ecosystem than Flutter or React Native. Microsoft has invested in recent versions primarily in quality and performance. In .NET 10, experimental support appeared for running on CoreCLR on Android instead of the Mono runtime. Also for mobile, it’s worth mentioning that Avalonia and Uno Platform, presented in the desktop article, reach iOS and Android.

Choose MAUI when: the team is .NET, the app is business-oriented (forms, lists, synchronization with an ASP.NET Core backend), you want to reuse Blazor components, or you are migrating an existing Xamarin.Forms app.

PWA: the app that doesn’t go through the store

Before any mobile framework, it’s worth asking: do you really need an app in the store? A PWA is a web app that can be installed on the home screen, works offline via service workers, and updates with every deploy, without review and without users doing anything.

On Android, PWAs are very well supported. The browser can suggest installation, push notifications work, and a PWA can even be published in Google Play via a Trusted Web Activity.

On iOS, the situation is more complicated. Push notifications work from iOS 16.4 but only for apps added to the home screen. Installation is manual, from the Share menu, without an automatic prompt. Background sync and access to Bluetooth or NFC are missing, and storage space can be cleared by the system after a long period of non-use. For those in the European Union, it’s good to know that Apple abandoned in 2024 the plan to remove web apps from the home screen in the EU, so PWAs continue to work here.

Choose PWA when: the app is mainly forms, lists, and content, users can be instructed to install it (as happens with a company’s internal apps), and hardware needs are limited to camera and GPS.

The hidden costs of an app in stores

Comparisons between frameworks usually stop at code. But a mobile app has a maintenance cost that doesn’t appear on the web, regardless of the chosen technology:

  • Accounts and review. The Apple developer account costs annually, and the Google Play one only once. Each version goes through a review that can last from a few hours to several days and sometimes ends with rejection.
  • Builds for iOS. You need macOS and Xcode, on your own Mac or in a cloud build service.
  • Mandatory annual updates. Google Play requires apps to target a recent Android version, and Apple requires builds with recent SDKs. Even if the app receives no new features, it must be rebuilt and republished periodically.
  • Old versions in production. On the web, all users always have the latest version. On mobile, some users stay months on old versions. For the backend, this means API versioning and compatibility with older versions, plus a forced update mechanism for critical cases.
  • Push notifications. You need APNs for iOS and FCM for Android, usually unified through a service like Firebase Cloud Messaging or Azure Notification Hubs, plus device token management in the backend.
  • Updates without the store. Expo (for React Native) and Shorebird (for Flutter) allow delivering fixes directly to devices without a new review, within the limits allowed by store rules. For a small team, it’s worth considering.

What to do with apps left on Xamarin

Official support for Xamarin ended on May 1, 2024. The app doesn’t stop working, but the problem appears with updates: stores require builds with recent SDKs, which Xamarin no longer receives. Each year it becomes harder, then impossible, to publish a new version.

The natural path is migration to modern .NET:

  1. Xamarin.Forms migrates to .NET MAUI. Concepts, XAML, and much of the code are preserved, but custom renderers must be rewritten as handlers.
  2. Xamarin.Android and Xamarin.iOS migrate to .NET for Android and .NET for iOS, with relatively small changes.
  3. Before migration, check dependencies. Many NuGet packages for Xamarin are no longer maintained and must be replaced. Usually, this hides most of the effort.
  4. If the app has few screens and the team has changed in the meantime, compare the migration cost with a rewrite in Flutter or React Native. It’s not always obvious which is lower.

Decision table

Situation First choice Serious alternative
Internal app, forms and lists PWA .NET MAUI
.NET team, business app .NET MAUI PWA or Flutter
SaaS in Blazor needing a mobile app .NET MAUI + Blazor Hybrid PWA
React team, product app React Native with Expo PWA
Branded UI, identical on iOS and Android Flutter React Native
The app is the main product, large budget Native (SwiftUI + Compose) Kotlin Multiplatform
Android team wanting iOS too Kotlin Multiplatform Compose Multiplatform
Advanced platform features (AR, widgets, watch) Native Flutter with native code
Existing Xamarin.Forms app Migration to .NET MAUI Rewrite in Flutter

The most common mistakes I see

  • App in the store for image. “To be in the App Store” is not a technical requirement. If users are company employees, a well-made PWA solves the problem at a fraction of the cost.
  • Offline added at the end. Offline work is not a feature but an architecture: local database, sync queue, conflict resolution. If it’s a requirement, it must be designed from day one.
  • API without versioning. The first incompatible backend change blocks all users who haven’t updated the app.
  • Testing only on new phones. Real users have phones three years old, with little memory and weak signal. Test also on a cheap Android.
  • Framework chosen by language, not by team. A .NET team choosing Flutter just because it’s popular will spend the first months learning Dart, Flutter, and its ecosystem instead of delivering.
  • Postponed migration from Xamarin. Each month of delay shortens the period in which you can still publish updates without a crisis.

Summary

  • Native offers the best experience and immediate platform access, at the cost of two codebases. Kotlin Multiplatform reduces duplication without giving up native UI.
  • Flutter offers an identical interface everywhere and excellent productivity, with Dart and its own rendering engine.
  • React Native is the natural path for React teams, and with the new architecture and Expo it’s much more mature than a few years ago.
  • .NET MAUI is the natural choice for .NET teams and the only one that brings Blazor components to the phone, but the ecosystem is smaller and the reputation mixed.
  • PWA is the option worth checking first. It’s excellent on Android and has clear limits on iOS.
  • Hidden costs (review, mandatory annual updates, old versions in production) matter more than the choice of framework.

In the last article of the series, we put everything together and answer the hardest question: how much code can you actually share between web, desktop, and mobile? We compare .NET MAUI, Avalonia, Uno, Flutter, Compose Multiplatform, and React Native on the same scenario, see what shares easily and what doesn’t, and finally build a decision table for the whole series.