.NET MAUI promises to make native development much easier, especially if you already know how to build for the web.
If you’re using or considering using Blazor, you’re probably thinking about building web applications.
But with .NET MAUI you’ll soon be able to take that web app and run it on Android, iOS, Windows or MacOS too.
.NET Multi-platform App UI (MAUI) is a cross-platform framework, currently in development at Microsoft. It enables you to build cross-platform apps with a shared code base that can run natively on Android, iOS, macOS and Windows.
Out of the box, .NET MAUI framework provides support for data-binding; cross-platform APIs for accessing native device features like GPS, accelerometer, battery and network states; a layout engine (for designing pages) and cross-platform graphics functionality (for drawing, painting shapes and images).
The promise of .NET MAUI is that you’ll be able to build a single app and have it run on all four operating systems. But it goes even further when you add Blazor to the mix.
There are two primary ways you can build the UI for your .NET MAUI app: XAML and Blazor.
If you’ve ever built WPF applications, or even (dare I mention it) Silverlight apps, you know XAML. It’s a proprietary markup language, from Microsoft, for building a user interface that has been in use for several years in various guises.
Declarative in nature, it offers a way to compose your UI using markup and have that UI react to changes in the underlying data.
But XAML isn’t the only option for .NET MAUI—you can use Blazor too.
In practice, this means you can build a hybrid Blazor web application using Razor components, HTML and CSS that will run, natively, on all four of these operating systems.
This ability to create a native application with a UI written using HTML and CSS makes it a particularly useful option if you’re already comfortable building for the web. It means you can take all your existing knowledge, skills and experience, and turn it toward building a native app.
At this early stage, it looks like there are three primary use cases for adopting .NET MAUI (with Blazor).
.NET MAUI ships with a handy control called BlazorWebView
.
The name here can be a little misleading, as it conveys a sense that you’re still running your Blazor app as a web application, somehow disconnected from the native hardware of the device you’re running it on.
In reality, while BlazorWebView
is indeed enabling you to host your Blazor web app in a .NET MAUI app, the app isn’t running on WebAssembly (as you might initially assume) or some other browser-based technology.
You don’t need a web server or some other way to host your application.
Your .NET Blazor hybrid app will be running 100% natively, on the device, not via HTTP and not contained within the browser sandbox (which you’re usually limited to when running a web application).
Indeed, the only “web” part of your application is the UI, which is built using HTML and CSS and rendered into a web view control. All your actual code, application and business logic is running locally on the device.
As a result, Blazor with .NET MAUI offers a convenient way of building your application, using familiar paradigms, tooling and design-time experience, while bringing the benefits of running a native application (including access to native APIs like GPS and accelerometer APIs for the native device).
You’ll need a .NET MAUI project.
Then you can declare an instance of the BlazorWebView
control, pointing to whichever Razor Component you want to render.
<b:BlazorWebView HostPage="wwwroot/index.html">
<b:BlazorWebView.RootComponents>
<b:RootComponent Selector="#app" ComponentType="{x:Type local:Main}" />
</b:BlazorWebView.RootComponents>
</b:BlazorWebView>
In this example we’re attempting to render a Main
component (located within the MAUI Client App).
You can have more than one BlazorWebView
, opening up the possibility of building a .NET MAUI app that uses Blazor for some but not all of your UI (potentially using multiple BlazorWebView
controls to render various components in multiple places in your .NET MAUI app).
You also have the option of rendering components that are defined within a Razor Class Library.
With this, you can create shared components that are defined in a Razor Class Library and then consumed by both Blazor Server/WASM and .NET MAUI clients.
In this example, we have a Blazor Server App (which leans on ASP.NET and runs via .NET on the web server) and a .NET MAUI app (running on the device and platform specific version of the .NET framework) both able to render components from the shared Razor Class Library.
This is all well and good, but what if you need to change the way your application works, depending on which platform you’re running on?
For example, say you wanted to render a button to enable users to take a photo using the camera on iOS and Android, but not on Windows or MacOS.
In that scenario, you can make calls from a Razor component located within your .NET MAUI app to check which OS the app is currently running on.
bool showCameraButton = OperatingSystem.IsAndroid() || OperatingSystem.IsIOS();
You can then render parts of your UI based on those platform capabilities.
@if(showCameraButton){
// camera button here!
}
One thing you’ll need to consider, when building a .NET MAUI Blazor app, is where to define your components.
If you’re building a .NET MAUI app with no requirement to run on the web, this is fairly straightforward. But if you’re attempting to share components between Blazor Server/WASM and .NET MAUI, you’ll need to give a little thought to which parts of your application should be shared and which should be more platform-specific.
For example, the conditional code above (for showing a camera button) really needs to live in a .NET MAUI client app, as that’s where you can detect the underlying OS.
Try to find out if you’re running on Android in a Blazor WASM app and you’ll likely be left disappointed!
This might leave you wondering how you’d handle conditional UI in a shared component. For example, if you had a shared component in a Razor Class Library and needed to use conditional logic to alter its appearance or behavior depending on the underlying platform.
The trick is to push that logic higher up, into a component that runs in the .NET MAUI app, and let it pass a parameter down to the shared component, which can then determine its own fate.
Here we’d let the Main
component in the .NET MAUI app check which platform we’re running on, then pass that information (as a parameter) to the shared Gallery
component.
Main.razor (MAUI client)
<Gallery EnableCameraButton="@enableCamera" />
@code {
private bool enableCamera = // platform checks to decide;
}
Gallery.razor (Razor Class Library)
@if (EnableCameraButton)
{
<button>Take a Picture</button>
}
@code {
[Parameter]
public bool EnableCameraButton { get; set; }
}
This begs the next question: What if someone clicks the button? Then we’d want to invoke the native API to actually launch the camera on the device.
We can’t put that sort of code in the shared component, but we can send a signal when the “Take Picture” button is clicked.
For that, we can use an EventCallback
to flag up that the button was clicked.
Gallery.razor (Razor Class Library)
@if (EnableCameraButton)
{
<button @onclick="CameraButtonClicked">Take a Picture</button>
}
@code {
[Parameter]
public bool EnableCameraButton { get; set; }
[Parameter]
public EventCallback CameraButtonClicked { get; set; }
}
We can then react to that event in the .NET MAUI app.
Main.razor (MAUI client)
<Gallery EnableCameraButton="@enableCamera" CameraButtonClicked="@OpenCamera" />
@code {
private bool enableCamera = true;
void OpenCamera()
{
// call platform specific code to open the camera
}
}
With this approach, we’ve successfully kept only the code that makes sense for native devices in the .NET MAUI app and still managed to use a shared component (from a Razor Class Library).
At the time of writing, .NET MAUI Preview 13 is available for use with Visual Studio 2022 Preview (17.2 Preview 1).
According to the official roadmap, we can expect a GA (general availability) release of MAUI for .NET 6 in Q2 2022, with a .NET 7 version to follow in Q4 2022.
Jon spends his days building applications using Microsoft technologies (plus, whisper it quietly, a little bit of JavaScript) and his spare time helping developers level up their skills and knowledge via his blog, courses and books. He's especially passionate about enabling developers to build better web applications by mastering the tools available to them. Follow him on Twitter here.