RIP Xamarin: Adding .NET MAUI to RUM

| 8 min. (1529 words)

We’re constantly seeing frameworks evolving and churning, and in May 2024 we’ll see the end of Xamarin after 12 years. The deprecation of Xamarin means we need to ensure that MAUI is equipped with the tools and functionalities that developers have come to rely on Xamarin for. At Raygun, that’s Real User Monitoring (RUM). To prepare for this shift, I’ve been working on the integration of RUM for our Raygun4Maui provider, offering features like page tracking, session insights, custom and native timings, and network timings, alongside vital stability improvements.

In this blog, I’ll discuss these recent enhancements and how I’ve been adding RUM capabilities for an excellent developer experience across Windows, Android, iOS, and MacCatalyst platforms. I’ll also discuss my experience on this project and what I’ve learned while using the .NET MAUI framework.

Hang on, what’s Real User Monitoring (RUM)?

As existing Raygun customers know, understanding user interactions with your application is crucial to creating great software experiences. RUM allows us to optimize user experiences with concrete data on both how our applications are being used and how they are performing.

Our goals

One of our main goals with this new feature set is to keep it as familiar as possible to existing Xamarin users, while also conforming to current best practices. Luckily, we have an existing Xamarin provider we can pull inspiration from, plus a wealth of software development learnings since Xamarin was released.

Overall, Xamarin and MAUI are very similar, with MAUI being an evolution rather than an entirely new framework. This is great for existing Xamarin developers, as transitioning to MAUI won’t require too much of a mental shift. There are, however, some key differences that I’ve encountered, which make developing in MAUI just a little bit nicer. This includes exposing the app lifecycle listeners through the MAUI app builder, which simplifies the process of handling app events such as start-up, sleep, and resume among others, directly within the app’s main configuration.

Another notable change is the focus on unified project structures, which streamlines the development of multi-platform apps by eliminating the need for multiple separate projects for each platform. While you can still have platform-specific projects to include, MAUI provides a robust feature set so that you won’t need to do this most of the time. This was a great help when I was working on our new changes, as I was able to keep our Raygun4Maui provider as one project that could handle it all with minimal platform-specific code.

There are many more features that MAUI brings to the table, and this blog could be just about that, but for brevity I’ll move on to the ones I’m really proud to show off.

Page tracking and load times

One of the most important features for RUM is page tracking and load times. Knowing how users navigate your app or website and where the pain points are is really valuable. I’ve gained some valuable insights on one of my personal projects using the Raygun4JS provider in a project that I never thought of adding logging to.

Technical readers might want to know how exactly we calculate these timings in our updated provider. We unfortunately don’t get direct access to low-level information on how the app is operating and page navigation, which makes it difficult to get real measurements of load times. MAUI does, however, expose hooks for the PageAppearing and PageDisappearing. With these, we can measure the time between the current page disappearing and the next page appearing, providing us with a pseudo-measure of load time.

MAUI session tracking in RUM

Being quite new to Raygun, I’ve been discovering how the products work together while developing the RUM feature set. A really neat feature that ties RUM and Crash Reporting together is when there is a crash report, you can find these under the page below the session tab. I could follow the path the user (myself in this case) navigated throughout the application and where exactly the error occurred. It’s a small detail, but I really appreciated the way the information was arranged in Raygun.

Session Tracking

The session tab, as mentioned, is the place where you can view the path a user took throughout the session – but there’s a lot more information that is both viewable and stored. Included in the RUM payload are fields for the user, app version, operating systems and versions, and device model. This gives you insights into which platforms people use to access your app, what operating systems are being used, and a whole lot of other information that is indexable in Raygun. Combined with Crash Reporting, which reports even more environment information, you can get a significant amount of usage information which is invaluable for creating better software experiences.

Metrics in RUM

Network Timings

This is the feature I spent by far the most time on. Timing the network requests going in and out, surprisingly, is very hard to do in the background.

But first, what are we measuring and why does this matter? Network timings tell us how long a network request took and what endpoint was being requested. One of the slowest operations to do in both web and app development is a network request, so having concrete metrics on the response times is another great measure of the responsiveness of your app. Just hitting these endpoints from your local machine can’t give you real-world data; so I really enjoyed working on this feature as I know how valuable it is.

Network calls in RUM

There is one caveat to the networking implementation. Windows, iOS, and MacCatalyst all work out of the box with the HttpClient, but Android requires that you use the URL and HttpURLConnection objects provided by the Java.Net namespace. This is due to the AndroidHttpResponseMessage implementation in Xamarin.Android not calling disconnect on disposal.

Working on this feature was a cool experience. Getting to leave .NET land for a bit and trying out Objective-C and Java to create some native binding libraries was a great change of pace.

Chronologically, this was the final feature I added as part of these changes to enable RUM. (If you are already familiar with breadcrumbs, you’ll know this is a Crash Reporting feature and not a RUM feature. Surprise!) Breadcrumbs are a new enhancement to the Crash Reporting feature set, and not just limited to our MAUI provider. This is now available on both the Raygun4Net.NetCore and AspNetCore providers as well. Users of our Xamarin provider will already be familiar with breadcrumbs, but up until now, we haven’t supported this outside of .NET Framework.

For those who don’t know what breadcrumbs are, it’s a reference to the story of Hansel and Gretel. Think of it like leaving a trail of breadcrumbs announcing your location so that when you receive a crash report, you can follow the trail right up to the crash event.

Breadcrumbs in Raygun

Practical tips/How-to

I’ve also made some larger changes in how we attach the Raygun4Maui provider to a MAUI app. These changes should hopefully make it easier to work with our provider and also bring it more in line with existing patterns for setting up services.

The Raygun4MauiSettings object has had a bit of refactoring with the removal of unnecessary inheritance and the addition of RUM-specific settings, so if you’ve already been using our old provider you’ll need to make some changes. We now support pulling in the Raygun4MauiSettings from a configuration file such as appsettings.json, alongside in-code definitions of the settings. Adding this allows for even more flexibility in how you decide to use our provider. Below is an example, appsettings.json, which enables some of the key features that I’ve mentioned throughout this blog.

{
 "Raygun4MauiSettings": {
   "RaygunSettings": {
     "ApiKey": "paste_api_key_here",
     "ApplicationVersion": "1.0.0",
     "CatchUnhandledExceptions": true
   },
   "RaygunLoggerConfiguration": {
     "MinLogLevel" : "Warning"
   },

   "IgnoredViews": ["LoginView", "SettingsView"],
   "IgnoredUrls": ["https://example.com/ignore"],
   "EnableRealUserMonitoring": true,
   "RumFeatureFlags": "Network, Page, AppleNativeTimings"
 }
}

Looking for further examples of how to use the Raygun4Maui provider? We’ve got a sample app you can check out under the Raygun4Maui repo. We also have thorough docs which should explain all the features and how to use them.

Wrap-up

That’s the full account of the integration of Real User Monitoring (RUM) with the Raygun4Maui provider. I’m proud to say that with this feature update, RUM is helping MAUI and Xamarin developers to continue creating great software experiences through the understanding and optimization of user data. With page tracking and timings, session tracking, network timings, and breadcrumbs, we gain an even greater level of visibility throughout our applications. For me, this has been an interesting project, but also an excellent learning process where I’ve been able to familiarize myself with the Raygun ecosystem and collaborate with a bunch of smart developers.

If you’re looking for some more MAUI content, I’d suggest having a read of the Xamarin to MAUI migration guide and keeping up to date with the .NET 9 MAUI changes. One feature I’m looking forward to is the Swift Interop support. As we get closer to Xamarin being sunset, I’ll also be releasing another blog covering step-by-step how you can convert your Xamarin applications to MAUI. Also remember, MAUI itself can be fickle at times, so if you run into a wall, don’t give up!