In my free time I’m working on an application for a community I’m in and after a (boringly) lengthy process of evaluation/elimination with a few different technologies, I picked MAUI. I’ll leave the door open for me to explain that process and what was eliminated another day, I just wanted to note down my initial impressions/difficulties around specifically using MAUI for now in this post.
A little context about the technical constraints for my application: I want it to work on Windows, Mac, iOS, and Android. The only local device access it strictly needs is input (duh) and a place to store a sqlite database.
At the time I started investigating choices MAUI tooling support was immature enough to only exist in Visual Studio previews, so I wrote it off for that reason alone initially (especially because I prefer to use Rider, which had a little more catchup to do). There’s still a few teething issues with it now but it’s good enough to roll with and is usable in non-preview versions today.
To focus on the immediate positives: my existing knowledge, skill and enjoyment of C# and dotnet have made it a bit of a breeze to get something up and running quick. There has been very little knowledge gap to deal with before I could start building a back-end and tying it to a UI and this has allowed me to focus on building out the application and getting feedback much quicker than if I was wrestling with the (unknown to me) quirks of electron or something. A lot of the heavy lifting is done with the default project templates - you can effectively hit “File => New” then select your platform and run it, it’ll work. Unless you need platform-specific features, it looks like there’s no need to muddy yourself with platform-specific code beyond the default.
There’s a bit of a fork in the road (though I don’t think it’s strictly “either/or”) in MAUI where you get to pick between building a Blazor-oriented UI or a regular one. Neither experience gives you a strictly universal application - the Blazor application’s rendering engine changes based on operating system and the native controls are wildly different based on platform. I think this is a fine and normal thing in some respects as it helps you lean into what is typical of a given environment, but in contrast it makes things a bit less platform-ignorant than maybe I hoped. One vital thing to note here is that both options should be viable on all supported platforms but what wasn’t obvious to me at the start is that Linux is not a supported platform for MAUI at all even if you would reasonably assume a web-tech-based Blazor app would be a simple way to bridge that gap. Oh dear.
The native UI was broken for me on MacOS from the start. Components would overlap each other by default requiring me to divert my attention to restyling from the start and if I used fairly ordinary keyboard shortcuts when testing (like Cmd+A to select all text in a textbox) then the application would crash and shut down, seemed fine on Windows and Android though! Another issue is that documentation seemed a bit too scarce to get me up and running with a sensible architecture quickly, I could find surprisingly little around typical dependency registration/resolution in the app structure and instead only really “build your first app” style guides with everything declared fairly inline. I don’t know nor did I care to spend much time figuring these things out after a point as it was easier to switch and commit to Blazor. One thing I did like about “native UI MAUI” was the out-of-the-box Shell which made it far easier to start adding components to a visual structure that was halfway decent from the start. Not particularly innovative since I think it was brought forward from Xamarin Forms, but certainly welcome.
The Blazor UI is, for better or for worse, Blazor. All existing documentation around Blazor and razor pages just works great for it if you’re new to it all like I am, dependency resolution in pages works how you’d expect as documented from these things, there’s really no surprises here. Everything just sits nestled inside a <BlazorWebView>
node at the root of the XAML, which is auto-generated and very easy to forget about after creation:
<BlazorWebView HostPage="wwwroot/index.html">
<BlazorWebView.RootComponents>
<RootComponent Selector="#app" ComponentType="{x:Type local:Main}" />
</BlazorWebView.RootComponents>
</BlazorWebView>
The downsides are similar to building any web UI. You’re very much restricted to the decisions of the rendering engine (on MacOS, tab-navigation is problematic. On Windows, Chromium does not respect autocomplete=off
and they aren’t in a rush to change that) which I have been sad to hit so soon, and while there may be workarounds or other things I can do to overcome these problems to an extent they betray the secret: this is not typical desktop application behaviour. It doesn’t feel right sometimes (I can’t say I’ve felt similarly betrayed by Electron applications I’ve used). Perhaps the worst difference across engines is that using browser dev tools on mac isn’t supported today. Bleh.
Predictably, you’re in for a tougher ride if you don’t use Visual Studio and Windows today (even dotnet CLI seems to suffer). Sometimes I struggle to run the application twice without cleaning and rebuilding, sometimes building inexplicably complains of missing xml files. I can only hot-reload in Visual Studio today, and debugging MacOS in Rider simply doesn’t work yet.
Maybe once my application is mature I’ll go back and re-evaluate other choices again and see what I could’ve done differently but for now I’m not disgruntled enough with MAUI to put the brakes on and port. I’m confident I can achieve everything I want to do with it even if it’s less than ideal today. I hope many issues are a sign of understandable immaturity and I’ll be much happier in the near future - until then I just hope that I have hit the worst of it and there’s no more surprises.
My final critique is I just don’t like the names MAUI and Blazor, I hate saying them out loud and they feel like silly words for tech, no offense to Bill Gates.