Telerik blogs
DotNetT2 Dark_1200x303

.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.

What Is .NET MAUI?

.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.

Blazor and .NET MAUI?

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.

Who’s It For?

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).

  • As a web/Blazor developer, to take your existing Blazor app and run it natively on mobile and desktop
  • As a web/Blazor developer, to make a brand-new native app using your existing skills
  • As a desktop developer, to use Blazor for some or all of your app, potentially bringing in Blazor components from the community and/or any existing web applications to which you have access

How Do Blazor Hybrid Apps Work?

.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).

How Do You Use BlazorWebView?

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).

Sharing Components Between Web and Native Clients

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.

Blazor Server and MAUI clients sharing a RazorClassLibrary - A box to represent a Razor Class Library with arrows showing how both a Blazor Server and a Blazor MAUI client app can consume that library

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.

Handling Differences Between the Different Platforms

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!
}

You’ll Need To Consider Where To Put Your Application Code

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.

A MAUI client app passes parameters to a shared component - A .NET MAUI client app passes an EnableCameraButton parameter to a component called Gallery.razor which resides in a Razor Class Library

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).

When Is .NET MAUI Coming?

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 Hilton
About the Author

Jon Hilton

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.

Related Posts

Comments

Comments are disabled in preview mode.