Over the last week I’ve been exploring different ways to measure the time it takes for an app to launch and be ready for the user to interact with. I’ll go into more detail on this topic in subsequent posts but I wanted first to take a bit of a side track into thinking about the future for cross platform app development using .NET. In this post we’re going to discuss startup performance for apps built using .NET and how this could influence how the cross platform frameworks of today (XamarinForms/Maui and Uno Platform) evolve going forward.
The two cross platform app frameworks we’re going to talk about in this post are Xamarin Forms (and by association .NET Maui) and the Uno Platform. In a lot of ways these frameworks benefit from the same underlying technology, Xamarin iOS, Xamarin Android and UWP. This will evolve into .NET for iOS, .NET for Android and WinUI in the future but the points we’ll discuss in this post will still be applicable.
It’s worth observing that Xamarin Forms and Uno differ in that Xamarin Forms uses its own platform independent abstraction whereas Uno provides implementations for iOS, Android, etc based on a UWP app. This means that Uno doesn’t need to provide a platform implementation for UWP.
When it comes to iOS and Android both Xamarin Forms and Uno suffer from similar problems when it comes to defining the user experience, which results in a significant performance hit, particularly on Android. Both frameworks rely on the underlying platform components, subsequently suffering from the performance bottleneck of having to interop with the native platform.
When looking at startup performance I noted that both Xamarin Forms and Uno were significantly slower to start than an equivalent Flutter app. My testing was done on Android, since this is where most developers end up having to tune their application for performance. Given that none of the apps were doing anything on startup, other than rendering a very basic layout, it can only be assumed that the .NET based frameworks either needed to load more on application startup, or that there were some performance issues related to rendering the user experience. Note here that I did try an empty Xamarin Android application and it performed similar to a Flutter app on startup, suggesting that the performance hit with Xamarin Forms and Uno was mainly user interface related.
Let’s assume that the startup performance hit on Android for Xamarin Forms and Uno is entirely related to rendering the user experience, and more specifically related to the interop between the .NET based application and the underlying native platform. If this is the case, then should we be looking for a long term solution that eliminates, or at least significantly reduce, the interop cost? And more significantly, how does Flutter avoid having to pay this tax?
Answering this second question may provide a solution for the first. Flutter avoids paying the interop cost by simply avoiding using any of the native platform controls. Instead it treats the screen as a canvas on which it renders the layout for the app. With this in mind, we should be looking for ways to replicate this for .NET based applications.
What’s interesting is that both Xamarin Forms team (well, now the .NET Maui team) and the Uno team have already made a start in this direction. The .NET Maui team have invested in options for the rendering of controls using Skia and the Uno Platform already has a backend that uses Skia. The Uno Skia implementation was initially created to support WPF and Linux platforms but in theory there is no reason this couldn’t be used on any platform that supports Skia.
It would seem that migrating to using Skia for rendering would be the logical choice. However, there’s more to switching to Skia than simply rendering elements to the screen. For example, if the frameworks no longer use the underlying native controls, accessibility, and specifically tools like screen readers, become an issue. A lot more work (already done by Google as part of implementing Flutter) needs to be invested in order to make sure all the standard metaphors of the target platform are implemented.
Whilst Skia may be the long term future for .NET based cross platform applications, we’re a long way from that right now. The next milestones for both Xamarin Forms (.NET Maui) and Uno Platform will be to support WinUI/Project Reunion and of course .NET 6. This will be a convergence point for both frameworks as they roll out new versions that will support .NET 6 and Windows.
5 thoughts on “Startup Performance, Skia and the Future of Cross Platform Apps Built with .NET”
Did you try the profiled AOT startup on Android and measure startup times then? Also, measuring startup times while having debugger attached and running unoptimized debug builds, might differ from release builds. So if you didn’t already try that, measure the startup on release builds.
Interesting with the Skia rendering for controls, similarly what Flutter does. I bet big G did a bunch of things already with regards to accesibility etc.
I didn’t try profiled AOT but the comparison was on Release AOT builds without the debugger attached, so pretty fair comparison.
Yes, Google is way ahead of the game with regards to Skia rendering – they’ve already dealt with the accessibility side of things. If you run a Flutter app, you really can’t tell that it’s not a native app in most cases.
When I tried xamarin forms (and rejected the technology), startup performance hit really noticeable on Android .
But I think one of the main reasons was heavy use of reflection during startup. Reflection and performance do not come together.
I’ve heard that Net6 MiUi is trying to get rid of reflection, so it might be better.
I’ve ended up in creating own framework for rendering UI controls using Skia and abstraction for layouting them using native lists. Startup performance is much better than with the XF – less than 1s on Android, XF demo for dashboard only was several seconds. (app is taphome, available for Android, iOS and WPF)
I don’t think the move to Maui specifically will fix the performance – the reliance on native controls is a massive overhead and not easy to improve. If the entire framework was using Skia rendering then perf might jump.
Have you taken a look at Uno?
No, I haven’t checked Uno, I’ve only seen Uno Democrat Calculator app for Android and the startup is terrible. I’m considering using it to port my windows app to Mac but not to mobile.
Xamarin android apps with native controls can start pretty quickly, so I think it’s Xamarin Forms and its abstractiins what is slow, not native controls. In 2016 I had big app using only native controls and with the hype of Xforms I was testing to make hybrid native/Xforms app. Concept that some of the pages or new pages will be in Xforms and old will stay native. To my surprise, only the fact, that there is one Xforms page in app – not even visible at start (and 130 native activities) caused app to start 1.2 second slower. There was some Xforms Init() or something. Xforms at start use reflection to scan assemblies and looks for custom renderers.