Xamarin is dead. What should you migrate to?
Xamarin was once the primary choice for multi-platform app development, especially among enterprise customers. However, in May 2024, Microsoft completely stopped maintaining the Xamarin project in favor of their next-generation app development toolkit, MAUI (Multi-platform App UI). Despite MAUI being essentially a heavily modified fork of Xamarin Forms, it has accumulated a substantial number of differences, making the switch from Xamarin both costly and time-consuming.
First, MAUI uses a different runtime than Xamarin. This change has resulted in a number of unmaintained 3rd party dependencies becoming incompatible with the new framework, forcing developers to find alternative solutions or maintain the dependencies themselves. Second, MAUI has introduced several breaking API changes to view lifecycle, styling, dependency injection, and navigation. These changes require developers to refactor their existing Xamarin Forms codebase to adapt to the new APIs, which can be a significant undertaking.
Finally, despite being a major rework of the original framework, MAUI can suffer from many of the bugs and instability issues that plagued Xamarin Forms from the start. To make matters worse, MAUI breaks many of the workarounds that the community has discovered over the years to mitigate these issues. This situation leaves developers in a challenging position, as they need to find new ways to address these problems while adapting to the new framework.
Overall, the switch from Xamarin (specifically from Xamarin Forms) to MAUI has placed Microsoft in an odd spot. The changes are significant enough to consider MAUI a completely different framework from Xamarin, yet the benefits may not justify the effort required for migration. It's important to note that the migration from Xamarin.iOS and Xamarin.Android to .NET.iOS and .NET.Android is more streamlined compared to MAUI, since the UI layer (the primary pain point of both Xamarin Forms and MAUI) is not present in these platform-specific frameworks.
However, these platform-specific frameworks have their own set of challenges. One notable issue is the incomplete or outdated documentation, which can make it difficult for developers to find the information they need to effectively use these frameworks. This lack of up-to-date resources can lead to frustration and wasted time as developers struggle to navigate the intricacies of the frameworks. Another concern is limited adoption among app developers. With a smaller user base compared to more popular frameworks, there may be fewer resources, tutorials, and community support available for .NET.iOS and .NET.Android. Furthermore, the availability of third-party libraries for .NET.iOS and .NET.Android is limited compared to other popular frameworks. This scarcity of libraries can make it more challenging for developers to find pre-built solutions for common functionality, forcing them to build more integrations and libraries from scratch.
This situation has led many traditionally C#-driven firms to consider alternatives for the future direction of their mobile development efforts. In this article, we will review how MAUI stacks up against Flutter and React Native and explore whether it's worth investing in redeveloping the app in a new technology stack. We will compare the developer experience of each framework to help you make an informed decision for your mobile app development strategy.
Unlike Xamarin in the past, MAUI competes in a crowded market. The mobile app development landscape is currently has two primary options in React Native and Flutter amongst others. Both offer wide communities, large selection of 3rd party libraries and good documentation. React Native is somewhat similar to MAUI in underlying architecture, using platform-specific native components exposed to the multi-platform runtime (Hermes) via FFI interface. Flutter, on the other hand, is more similar to Avalonia from .NET ecosystem, using a custom rendering engine to render the UI fully on its own. When it comes to composing user interfaces, MAUI and frameworks like React Native and Flutter take different approaches. MAUI follows a more traditional approach, similar to Xamarin, where the UI is defined using XAML. XAML is a declarative language that allows developers to describe the structure and appearance of the UI using a hierarchical tree of elements. This approach is familiar to developers with experience in Microsoft UI frameworks like WPF and UWP.
On the other hand, React Native and Flutter adopt a more modern and flexible approach to UI composition. In React Native, the UI is built using JavaScript and JSX, a syntax extension that allows you to write HTML-like code within JavaScript. React Native uses a component-based architecture, where the UI is broken down into reusable components that encapsulate both the structure and behaviour of a part of the UI. This component-based approach promotes code reusability and makes it easier to manage and update the UI.
Similarly, Flutter uses a declarative UI approach with a widget-based architecture. In Flutter, the UI is composed of a tree of widgets, where each widget defines a part of the UI. Widgets are written using the Dart programming language, which allows for an expressive and flexible way of building UIs compared to XAML. Flutter's widget system is highly customisable and provides a rich set of pre-built widgets that can be easily composed and customised to create complex UIs.
A key advantage of React Native and Flutter's approach is that the UI is built using the same language as the application logic. This allows for a more seamless integration between the UI and the underlying logic, making it easier to create dynamic and interactive UIs. Additionally, the component-based and widget-based architectures in React Native and Flutter promote code reusability and modularity, making it easier to maintain and scale the application.
Let's take a look at an example comparing the composition of an animated box UI in MAUI and Flutter to illustrate the differences in their approaches:
MAUI
Flutter
React Native
The choice of technology stack for mobile app development is not only about the frameworks themselves but also the underlying programming languages. MAUI uses C#, while Flutter uses Dart and React Native uses JavaScript (or more commonly, its typed superset - TypeScript).
Comparing these languages to understand their strengths and differences.
When comparing C#, Dart, and TypeScript, it's important to note that all three are object-oriented programming languages with strong typing. However, there are some key differences to consider.
C#
C# is a mature language with a vast ecosystem, thanks to its long history and Microsoft's support. It offers a wide range of features and is well-suited for large-scale enterprise applications. On the other hand, Dart and TypeScript are relatively newer languages that have gained popularity in recent years.
TypeScript
TypeScript, developed by Microsoft, is a superset of JavaScript that adds optional static typing and other features. It compiles to plain JavaScript, making it compatible with existing JavaScript libraries and tools. TypeScript's popularity has grown significantly due to its use in Angular, a popular web application framework.
Dart
Dart, created by Google, is a standalone language that can be compiled to native code or transpiled to JavaScript. It has a syntax similar to C# and Java, making it easier for developers with experience in those languages to pick up. Dart's primary use case is for building web, server, and mobile applications, especially with the Flutter framework.
Despite TypeScript being developed by Microsoft, Dart is arguably closer and more familiar to C# developers. Dart's syntax and object-oriented programming model closely resemble C#, making the transition smoother for C# developers. Additionally, Dart's strong typing and support for async/await can make it feel like a natural extension of C#.
Is MAUI a good option?
One of the advantages of using MAUI for mobile app development is the ability to reuse the same models and business logic from the C# backend. This can lead to improved consistency and maintainability across the entire application stack. However, this advantage can also be somewhat achieved when using Flutter or React Native by leveraging code generation from OpenAPI specifications.
So which is best? Well it depends.
.NET has built-in support for generating client code from OpenAPI (formerly known as Swagger) specifications. This means that developers can define their API contracts using OpenAPI and automatically generate the corresponding models and API client code in C#. The generated code can then be shared between the backend and the mobile app, ensuring consistency and reducing duplication.
By adopting this approach, developers can enjoy the benefits of reusing models when using Flutter or React Native for the mobile app. The generated code can be easily consumed by the mobile app, regardless of the chosen framework.
Performance is a critical factor in mobile app development, and both Flutter and React Native offer significant advantages in this area compared to MAUI.
Flutter's custom rendering engine allows it to deliver high-performance, smooth animations and UI interactions. By leveraging Skia, a 2D graphics rendering library, Flutter can render UI components quickly and efficiently. Additionally, Flutter's ahead-of-time (AOT) compilation and use of native ARM code result in fast startup times and optimised performance.
React Native, on the other hand, leverages the native components of the underlying platform (iOS or Android) for rendering. This approach allows React Native apps to achieve near-native performance. The framework's architecture, which uses a separate thread for UI rendering and another for JavaScript execution, helps in maintaining a responsive user interface even during intensive background tasks.
In contrast, MAUI, being a relatively new framework, may still have some performance overhead compared to Flutter and React Native. The use of platform-specific native components in MAUI can introduce additional layers of abstraction, which may impact performance in certain scenarios.
Summing it all up
While there are similarities between Xamarin and MAUI, the effort required to migrate from Xamarin to MAUI should open the conversation about completely transitioning to a new technology stack. The challenges associated with MAUI, such as the different runtime, breaking API changes, and persistent bugs, make it worth considering alternatives like Flutter and React Native.
The similarities between Dart and C#, combined with the performance and productivity benefits offered by Flutter and React Native, justify the adoption of a new stack. Dart's familiarity to C# developers and its strong typing make it an attractive option for teams with a C# background. Additionally, the ability to generate API models and API client code from OpenAPI specifications addresses the advantage of reusing models and business logic, even when using Flutter or React Native.
Lastly, the performance advantages of Flutter and React Native cannot be overlooked. These frameworks have proven track records of delivering high-performance, responsive mobile apps that provide a native-like user experience.
Ultimately, the decision to migrate to a new technology stack should be based on a thorough evaluation of the project's requirements, team's expertise, and long-term goals. However, given the challenges associated with MAUI and the benefits offered by Flutter and React Native, it is worth considering a complete migration to leverage the full potential of these modern mobile app development frameworks.
If you’d be interested in discussing migrating your Xamarin application to a new cross platform framework, why not reach out to us on +61 (0)8 6381 9170.