I am wrapping up developing a .NET MAUI app targeting Windows, Android, and iOS.
Overall, I would say that despite all the hiccups it was exactly what I was hoping for. Most of the problems I experienced were a result of the immaturity of the platform early on, and have since been resolved.
Despite having no specific mobile development experience, I was able to make progress very quickly. And would be able to go even faster today.
I had done a bunch of Silverlight, WPF, DotVVM, and other XAML style development for ages, and XAML + MVVM is by far my favorite stack.
I first coded the app in Xamarin.Forms since MAUI hadn't been released. But migrating was fairly easy. The upgrade-assistant tool helped some, and having any experience with ASP.NET style dependency injection makes the new parts feel familiar.
Stuff I liked:
It provides an open source cross-platform stack for native application development in .NET, with support for the latest .NET versions.
It is more batteries-included than Xamarin.Forms. Lots of concepts from Xamarin Essentials, the Xamarin Community Toolkit, and the wider ecosystem were simply incorporated directly into the framework, and expanded upon. Like SVG support, built-in screenshots, geolocation, permissions, file pickers, dark mode detection, and other platform-agnostic helpers.
It interoperates very seamlessly with Blazor, so you would be able to share everything from your ViewModel layer and below.
You can even directly incorporate WebView2 controls that you can interact with pretty nicely, which should allow mixing in web content, such as React, Angular, or Blazor apps.
My application was able to use an offline-first approach via Entity Framework and SQLite. I ended up implementing a bi-directional offline sync between SQLite and SQL Server, and this was done very easily as a background syncing service via the Dotmim.Sync library. And I was able to completely share the DbContext between the clients and the server.
I didn't know this at first, but there is an awesome IQueryAttributable interface that you can implement to parse all query parameters in one central place, and this just feels vastly nicer to use than attributes.
MAUI/Xamarin Shapes are really cool for making programmable platform-agnostic vector graphics.
The MAUI Community Toolkit has a lot of nice things like the Popup control, StateContainer, DockPanel, FolderPicker, and MVVM helpers.
The newest .NET versions support so many cool features built-in, and you can turn on a ton of extra features (nullable types), roslyn analyzers (Roslynator, StyleCop), code formatting helpers (EditorConfig), static analysis tools (InferSharp), build pipeline enhancements (Reproducible Builds, Nuget lockfiles), and so on. With all these guard rails up, it feels like the space for errors is much lower.
Hiccups:
Took awhile for the integrated map control to be released but it is mostly here now. Needed to do a bunch of manual work to implement custom icons, Windows support, and MVVM support.
GUIDs didn't seem to be implemented in a byte-identical way across the client-server boundary, which broke the syncing if Guids were primary keys, so I switched to ULID via NUlid and all problems were resolved. It also has the benefit of being sortable, and encoding datetime information inside of it. I don't know where this Guid bug ultimately can be blamed, but this is the kind of mysterious thing that you may end up dealing with given that you are using different compiler toolchains on the different platforms. Mono and .NET are still not perfectly identical, even though they are converging.
Entity Framework migrations support for SQLite is still limited, but improving.
The new Single-Project concept is more trouble than it is worth right now. The old Xamarin.Forms per-platorm project approach worked better. The new single-project style will often trigger a build for all of the platforms when you are only meaning to run or publish a single one. And unit tests can be annoying to set up with the Single-Project approach because the target frameworks are incompatible. I find myself commenting out parts of the CSPROJ frequently to deal with these kinds of issues, and had to add a bunch of conditional restrictions to various tags. These issues may just be growing pains.
Stuff I didn't like:
WinUI3 is still lacking basic and critical features like camera support and a native map control. And it is the only supported Windows target.
Encountered a fair amount of bugs. Most of them have been resolved, or I found workarounds, but new ones pop up as well. Expect some of this. Thankfully, the service releases come out monthly.
It feels like source generators are slowly taking over. It can be implemented really well sometimes, and there are lots of cool ones for regex and enums and such, but I didn't like the way it was done in CommunityToolkit.Mvvm. The magicalness of it is more of a downside than an upside. Also, I have experience with the older approach from PropertyChanged.Fody and friends, and that style seemed nicer. But you can just choose not to use them.
It supports so many fast-moving targets that are ultimately out of the control of the MAUI team, so a lot of things will inevitably break with new releases of Android, iOS, Mac, Tizen, and WinUI. The fact that it targets native controls on each of the platforms contributes to inconsistencies, and drawn controls are still a ways off.
Similarly, the submission processes to the various app stores can be challenging, and ever-evolving, but I eventually got the hang of it. Even things like version strings can be a challenge, and MAUI doesn't try to enforce a default versioning standard that will reliably work in all the stores. But it isn't a unified process. You use the Archive tool for Android and iOS, but use a separate wizard for Windows. Luckily, dotnet publish works as a consistent pipeline-friendly alternative. And EXE support on Windows is here too.
MAUI Shapes cannot be used as an ImageSource, which precludes easily using them in buttons, various libraries, etc.
There is no good free option for a DataGrid. But with a bunch of work I was able to adapt a basic open source library for my needs. I just made about a dozen PRs into that repo, so hopefully you will be able to benefit from my efforts.
I don't particularly like the UseMaui tag in the csproj since it just hides the package version. Useless magic. Luckily, nuget lockfiles can help keep it clear what service release you are on, etc. In addition to all the many other reasons to use lockfiles. Hope nuget turns them on by default sometime soon.
Top comments (0)