Telerik blogs

Blazor is welcome on mobile/desktop apps with .NET MAUI, and can pull off some pretty native functionality with platform API access.

This article is a part of MauiUIJuly calendar—a month-long list of wonderful content around .NET MAUI from the developer community, curated by Matt Goldman.

You may have heard the promise of Blazor Hybrid—bring Blazor web goodness to native mobile/desktop apps. Thanks to modern WebView components, developers can reuse Blazor components/styles/routing inside native apps—for .NET MAUI, WinForms and WPF.

As Blazor gets more usage inside mobile/desktop apps, one obvious developer question may be—can Blazor do native things? Would web developers have to go back into .NET MAUI to access platform features, or could they stay within the comforts of Blazor land? Thankfully, the answer favors Blazor developers and all of .NET MAUI’s platform API access is available from Blazor code. Let’s explore going native with Blazor.

Blazor with .NET MAUI

Blazor is the free, open-source and much beloved web framework for building modern web apps. Developers wanting to stay away from JavaScript can leverage the power of .NET, C# and modern tooling to build interactive beautiful web apps. The Blazor component model, rendering engine and styling mechanisms offer flexibility—there is also plenty of UI help with component libraries like Progress Telerik UI for Blazor.

.NET MAUI is the evolution of .NET cross-platform development strategy—a framework for creating native mobile and desktop apps with full platform API access. .NET MAUI also brings in a wonderful UI component called the BlazorWebView—an abstraction that hosts evergreen browser components on respective platforms and allows for rendering of web artifacts within the shell of native apps.

Blazor and .NET MAUI are almost made for each other, sharing the exact .NET runtime—.NET 6 yesterday, .NET 7 today and .NET 8 tomorrow. Blazor apps can now be easily hosted inside .NET MAUI apps, with full native platform integration. Blazor Hybrid apps, as they are called, enable a lot of code sharing across web and native apps on mobile/desktop. While Blazor can power app UI across web and native platforms, developers can cater varying UX and styles across platforms.

Platform API

Today’s .NET is open source and a cross-platform developer platform with solid tooling. Modern .NET helps developers build native apps for various mobile/desktop form factors and a plethora of devices. With Xamarin, Xamarin.Forms and now .NET MAUI, .NET code stretches easily to iOS, Android, Windows and macOS, with full access to native platform APIs.

Developers, however, would rather use native platform APIs from .NET/C# code, with underlying platform mappings exposed through abstractions. Without this, .NET developers would have to learn Java/Swift/Objective-C to access native APIs and, even worse, replicate native access code for each platform.

Platform API access from .NET has evolved over the years, from Xamarin Plugins to the combined NuGet dependency of Xamarin Essentials. With .NET MAUI, the initial thought was to port everything over as .NET MAUI Essentials—but platform API is one of the key benefits and it made sense to have everything baked in.

Platform API access from .NET MAUI is broken into logical granular namespaces—like Microsoft.Maui.ApplicationModel, Microsoft.Maui.Devices, Microsoft.Maui.Media or Microsoft.Maui.Networking. Thankfully, developers do not need to remember to bring in these namespaces to gain platform API access—default .NET MAUI templates bring in and pre-wire all the requisite namespaces for complete API access. All the power to reach into native device capabilities of mobile/desktop form factors is now at the fingertips of .NET MAUI developers—abstractions mean plain C# is all that is needed for cross-platform API implementations.

And for developers bringing in Blazor goodness to .NET MAUI through Blazor Hybrid apps, all of the platform API access is available right from Blazor code itself. After all, both Blazor and .NET MAUI use C# for business logic and share the common .NET runtime underneath. Web developers bringing in their Blazor UI components to mobile/desktop, have access to all the power of .NET MAUI platform API access—without having to do anything different. Let’s explore going native from Blazor code.

Device Info

The .NET MAUI with Blazor project template is a great way to get started with Blazor Hybrid—the scaffolded project includes Blazor UI components hosted inside a BlazorWebView within a .NET MAUI app. The point is, it is very much a native mobile/desktop app made with .NET MAUI, that just happens to render Blazor web UI on a WebView canvas. Blazor isn’t running on a web server or using WebAssembly—it is on the metal running on the same .NET runtime like the rest of the .NET MAUI app. When the app runs on mobile/desktop form factors, there are loads of device sensors that .NET MAUI offers API access to—and Blazor code can do the same.

Let’s add a button to the default index.razor page and pull up some device information from Blazor code, like so:

@page "/"
<h1>Hello, world!</h1>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />

<button @onclick="DoNativeStuff">Show Native Info</button>
<h3>@message</h3>
<h3>@deviceinfo</h3>

@code
{
    private string message;
    private string deviceinfo;

    void DoNativeStuff()
    {
        message = "Hello from " + AppInfo.Name + " running as " + DeviceDisplay.MainDisplayInfo.Orientation + " on " + DeviceDisplay.MainDisplayInfo.Width + "x" + DeviceDisplay.MainDisplayInfo.Height;

        deviceinfo = DeviceInfo.Name;

        var connection = Connectivity.NetworkAccess;
        if (connection == NetworkAccess.Internet)
        {
            var profiles = Connectivity.ConnectionProfiles;
            if (profiles.Contains(ConnectionProfile.WiFi))
            {
                deviceinfo += " on WiFi.";
            }
        }
    }
}

As evident, platform-specific APIs can offer up a variety of device information—like device name, orientation, screen dimensions and what network the device is running on. All of this is very native platform API access available in .NET MAUI—but also in Blazor razor pages. We can run the app in any mobile/desktop platform and see the APIs returning pertinent device information.

We could change device orientation on simulators/actual devices or switch networks—the same APIs return different values, as expected:

Read/Write to Disc

One platform feature most mobile/desktop apps might end up needing is disc access—reading and writing content from the app to the underlying file system. Given .NET MAUI apps run on iOS, Android, Tizen, Windows and macOS, the variations in OS implementations of disc access is vast—developers should not be expected to know how each platform does things under the covers. Thankfully, .NET MAUI platform APIs offer easy disc access across platforms, and they are fully accessible from Blazor code.

Let’s write a little bit of code in the counter.razor Blazor component to read and write from disc, like so:

@page "/counter"
...

<br/><br/>
<button @onclick="WriteToStorage">Write to Storage</button>
<button @onclick="ReadFromStorage">Read from Storage</button>
<br/><br/>
<p>Last used TimeStamp: @lastUsedTimeStamp</p>

@code {
    private string lastUsedTimeStamp;

    private void WriteToStorage()
    {   
        lastUsedTimeStamp = DateTime.Now.ToString(); 
        Preferences.Set("Last_Used", lastUsedTimeStamp);
    }

    private void ReadFromStorage()
    {
        lastUsedTimeStamp = Preferences.Get("Last_Used", "default_value");
    }
}

If we have to read/write a basic timestamp to disc across platform implementations, the Preferences API in .NET MAUI offers an easy key-value based dictionary for storage—perfectly accessible from inside a Blazor component. When the app is run, we can write and read the timestamp from disc, without knowing implementations across iOS/Android/Windows/macOS.

If developers need to read/write sensitive content to disc, .NET MAUI does offer a SecureStorage cross-platform API—this however needs additional permissions on some platforms, like Keychain entitlement on iOS or updated Backup manifest on Android.

private void WriteToStorage()
{   
    lastUsedTimeStamp = DateTime.Now.ToString(); 
    await SecureStorage.SetAsync("Last_Used", lastUsedTimeStamp);
}

private void ReadFromStorage()
{
    lastUsedTimeStamp = await SecureStorage.GetAsync("Last_Used");
}

Media

Native mobile/desktop apps often deal with multimedia needs—mobile devices, in particular, get extensive use for photos/audio/video through device cameras. Working with media isn’t difficult for .NET MAUI developers and the same is true if doing Blazor with .NET MAUI—the same APIs can be invoked from C#. The first step, however, is declaring app intentions with device permissions, as in Info.plist for iOS:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    ...
    <key>NSPhotoLibraryAddUsageDescription</key>
    <string>Need photo library access for spying.</string>
</dict>
</plist>

Next, let’s try to pull up the device media gallery from Blazor code, have the user select an image and display it back inside a Blazor component—here’s a little code in counter.razor:

@page "/counter"
...

<button @onclick="PickPhoto">Pick a Pic!</button>
<img id="chosenPic" src=@imageURL />

@code {
    private string imageURL;

    private async Task PickPhoto()
    {
        var result = await MediaPicker.PickPhotoAsync(new MediaPickerOptions
        {
            Title = "Just choose, will ya?"
        });

        imageURL = "./" + result.FullPath;
    }
}

The .NET MAUI MediaPicker APIs shine when working with device camera/media library and Blazor code can fire up the same Async-Await APIs.

Once a user selects an image from media library, we can read the file path of the image and display it back inside a Blazor component—all with an HTML img tag.

You may have noticed that the image displays nicely centered within the Blazor view—that’s done with hint of CSS inside counter.razor.css, as per Blazor styling conventions.

img{
    max-width: 100%;
    height: auto;
}

GeoLocation

The default .NET MAUI with Blazor template includes a FetchData.razor component that pulls up some fake weather data from an inbuilt service. With Blazor UI rendering inside a native .NET MAUI app, perhaps we do not need to fake weather—we can read the user’s geolocation just as easily from .NET MAUI platform APIs. The first thing again is to make sure we have all the permissions defined for each platform—here’s Info.plist for iOS.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    ...
    <key>NSLocationWhenInUseUsageDescription</key>
    <string>Need location access for stalking.</string>
</dict>
</plist>

When the user navigates to the pertinent Blazor view, the OS should pop up the familiar modal dialogue to ask for user permission before sharing geolocation information with the app. This is exactly as expected when a .NET MAUI app requests geolocation data—no different if the UI is painted with Blazor components.

The reason why we get the geolocation permission prompt is because our Blazor view tried reading user’s location data—here’s the code:

@page "/fetchdata"
...

<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from a service.</p>
<h3>@locationdata</h3>

...

@code {
    ...
    private string locationdata;

    protected override async Task OnInitializedAsync()
    {
        ...

        var location = await Geolocation.GetLastKnownLocationAsync();
        if (location != null)
        {
            locationdata = "Device Location: " + location.Latitude + " | " + location.Longitude;
        }
    }
}

With user’s permission, we can easily read geolocation data in terms of latitude and longitude—and display it within our Blazor component. Armed with real geolocation information, it should be a piece of cake to pull out real weather data for a given location.

P.S. Telerik UI for Blazor ups the game for Blazor web developers—100+ native Blazor UI components that are customizable and highly performance tuned to elevate app UX. And all of Telerik UI for Blazor now works outside of the web on native mobile/desktop apps—with official support for Blazor Hybrid apps.

Conclusion

.NET MAUI invites Blazor web developers to native land—web UI components and styles are now welcome on mobile/desktop form factors. While Blazor brings web goodness outside of the browser, there is no reason why developers cannot pull off native functionality on mobile/desktop devices—all of .NET MAUI’s platform API is accessible from C# Blazor code. Developers have more ways of mix and matching web with native UI, and enable more code sharing. Cheers to that.


SamBasu
About the Author

Sam Basu

Sam Basu is a technologist, author, speaker, Microsoft MVP, gadget-lover and Progress Developer Advocate for Telerik products. With a long developer background, he now spends much of his time advocating modern web/mobile/cloud development platforms on Microsoft/Telerik technology stacks. His spare times call for travel, fast cars, cricket and culinary adventures with the family. You can find him on the internet.

Related Posts

Comments

Comments are disabled in preview mode.