.NET MAUI Devs Wrestled with iOS App Size, Android Startup

Microsoft struggled to improve .NET MAUI performance beyond that of Xamarin.Forms, wrestling with thorny issues like iOS app size and Android startup times.

According to a lengthy, painstakingly detailed blog post about those struggles, it worked for .NET MAUI (.NET Multi-application UI), which just hit General Availability status on its path to replace Xamarin.Forms, including the ability to create desktop apps in addition to mobile apps.

"Our goal was for .NET MAUI to be faster than its predecessor, Xamarin.Forms, and it was clear that we had some work to do in .NET MAUI itself," said Jonathan Peppers, senior software engineer, in a gargantuan June 7 post titled "Performance Improvements in .NET MAUI."

He said the team believed that gains in developer productivity shouldn't come at the cost of application performance.

"The same could be said about application size -- what overhead is present in a blank .NET MAUI application? When we began optimizing .NET MAUI, it was clear that iOS had some work needed to improve application size, while Android was lacking in startup performance," he continued.

To strike a balance between app size and startup performance, the team addressed a dizzying array of concerns with many tests and tweaks that fine-tuned aspects ranging from different kinds of ahead-of-time (AOT) compilation to lazy loading to Dependency Injection to optimized color parsing and hundreds more.

Take AOT, for example, a big sticking point in the .NET world as the lack of officially supported native AOT actually kept developers away from the framework, according to a 2020 Microsoft survey.

AOT was found to be faster than just in time (JIT) compilation, as the latter happens the first time each C# method is called and thus implicitly impacts startup performance, which is a huge concern in mobile apps. However, AOT increases app size, because, for example, an Android native library is added in the final app for every .NET assembly, boosting the amount of code that needs to be loaded up. This conundrum required a balanced trade-off, a compromise that's prevalent in software development.

"To give the best of both worlds, startup tracing or Profiled AOT is a current feature of Xamarin.Android," Peppers said. "This is a mechanism for AOT'ing the startup path of applications, which improves launch times significantly with only a modest app size increase.

"It made complete sense for this to be the default option for Release builds in .NET 6. In the past, the Android NDK was required (a multiple gigabyte download) for doing AOT of any kind with Xamarin.Android. We did the legwork for building AOT'd applications without an Android NDK installed, making it possible to be the default going forward."

Through that and many other optimizations, the team did indeed lower startup times, as evidenced by the two graphics below, the first one showing test results for Android startup times in early previews, while the second one shows performance improvements "after the dust settled."

Android Startup Times in Early Previews
[Click on image for larger view.] Android Startup Times in Early Previews (source: Microsoft).
Android Startup Times After Optimizations
[Click on image for larger view.] Android Startup Times After Optimizations (source: Microsoft).

"To arrive at where we are today, it was a collaboration of several different teams," Peppers said. "We improved areas like Microsoft.Extensions and DependencyInjection usage, AOT compilation, Java interop, XAML, code in .NET MAUI in general, and many more."

While several developers lauded the team's efforts in the comments section of the blog post, one took exception, claiming performance boosts are secondary to more important concerns like missing features and functionality.

"Currently there are many cases where an API on a platform does nothing but [is] documented as working," said the comment. "Most importantly Essentials APIs. E.g. taking photos on Windows does nothing. Processing images using Maui.Graphics on Windows does nothing because they cannot be loaded as IImage (not fully implemented)! How can this be a full release? How can you release a feature that does not work -- taking look at the publicly available source code and seeing only parts implemented? I don't understand this behavior with MAUI."

About the Author

David Ramel is an editor and writer for Converge360.

comments powered by Disqus


Subscribe on YouTube