Add a PWA feature to our Blazor Maui Hybrid application

 

I have been working on a series of posts about the Maui Hybrid solution.  I create a desktop and Blazor web assembly web client that uses the same code for the UI and the same code for their backend services.

Just for fun or to see if it is even possible, I wanted the ability to deploy the solution as a Progress web app as well.  This gives users an additional way they can get the application and use it.  I have an older post about why you would want to build a PWA.


Turn Blazor Web Assembly web client into a PWA

The steps are fairly straightforward to archive this:

1. Create a Manifest File: 

    This is a JSON file that provides information about your application (such as name, author, icon, and description) to the browser. It's typically named manifest.json and placed in the wwwroot directory of your project. 


Here's a basic example:

{

  "short_name": "BlazorPWA",

  "name": "Blazor Progressive Web Application",

  "icons": [

    {

      "src": "icon-512.png",

      "sizes": "512x512",

      "type": "image/png"

    }

  ],

  "start_url": "/",

  "background_color": "#3367D6",

  "display": "standalone",

  "scope": "/",

  "theme_color": "#3367D6"

}

2. Add Icons: 

You need to provide icons for your application. The icons should be placed in the wwwroot directory. The icons are used in various places like the home screen, app launcher, task switcher, splash screen, etc. You can use different sizes but a 512x512 icon is a good start.


3. Link the Manifest File: 

You need to link the manifest file in your index.html file (which is also in the wwwroot directory). You can do this by adding a link tag in the head section of the HTML file:

 

<link rel="manifest" href="manifest.json" />


4. Create a Service Worker: 

A service worker is a script that your browser runs in the background, separate from a web page, opening the door to features that don't need a web page or user interaction. You can use it to enable features like push notifications and background sync. In the context of a PWA, a service worker also allows you to handle offline scenarios.

Here's a basic example of a service worker (service-worker.js):

self.addEventListener('install', event => {
    console.log('Service worker installed');
});

self.addEventListener('fetch', event => {
    event.respondWith(fetch(event.request));
});

5. Register the Service Worker: 

 You need to register the service worker in your index.html file. You can do this by adding the following script:

<script>

    if ('serviceWorker' in navigator) {

        navigator.serviceWorker.register('service-worker.js')

            .then(reg => console.log('Service worker registered', reg))

            .catch(err => console.log('Service worker not registered', err));

    }

</script>

6. Enable PWA in Blazor: 

Starting from .NET 5, Blazor WebAssembly has built-in support for PWAs. You can enable it by setting the ServiceWorker property in the wwwroot/service-worker.published.js file to true:

   self.importScripts('./service-worker-assets.js');

self.addEventListener('install', event => event.waitUntil(onInstall(event)));

self.addEventListener('fetch', event => event.respondWith(onFetch(event)));


const cacheNamePrefix = 'offline-cache-';

const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`;

const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.dat$/, /\.blat$/, /\.json$/, /\.woff$/, /\.woff2$/, /\.html$/, /\.js$/, /\.css$/, /\.ico$/, /\.svg$/, /\.png$/, /\.jpg$/, /\.jpeg$/, /\.gif$/, /\.tiff$/, /\.wasm/, /\.mp3$/, /\.wav$/, /\.ogg$/, /\.m4a$/, /\.flac$/, /\.aiff$/, /\.wma$/, /\.3g2$/, /\.3gp$/, /\.mp4$/, /\.mov$/, /\.avi$/, /\.flv$/, /\.mkv$/, /\.mpg$/, /\.wmv$/, /\.ogv$/, /\.webm$/, /\.vob$/, /\.mng$/, /\.asx$/, /\.asf$/, /\.rm$/, /\.rmvb$/, /\.m3u$/, /\.wmv$/, /\.mpg$/, /\.mpeg$/ ];

const offlineAssetsExclude = [ /^service-worker\.js$/ ];


async function onInstall(event) {

    console.info('Service worker is installing.');

    self.skipWaiting();

    const assetsRequests = self.assetsManifest.assets

        .filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url)))

        .filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url)))

        .map(asset => new Request(asset.url, { integrity: asset.hash }));

    await caches.open(cacheName).then(cache => cache.addAll(assetsRequests));

    console.info('Service worker installation complete.');

}


async function onFetch(event) {

    let cachedResponse = null;

    if (event.request.method === 'GET') {

        cachedResponse = await caches.match(event.request);

        if (cachedResponse && !navigator.onLine) {

            console.info('Returning cached asset:', event.request.url);

            return cachedResponse;

        }

    }

    return fetch(event.request);

}

That is all you need.  Or you could do what I did.  Create a new Blazor web assembly project and select to make it a PWA, then copy over the files you need.  It is best if you manually update the index.html file, just to be safe.

Now when you run the web client you will see an icon in the URL box letting you know you can install the application.


Summary

 I have to admit, this project is so cool.  I can now build applications that run on Windows, Mac, iOS, and Android all of which use the same code for UI and back-end services.  In addition, they can be deployed as a desktop, a web client, or as a progress web client.  This gives the user a great set of choices with no real maintenance for the application. You build the application for one platform, and you get just the rest for free.

One note to keep in mind, if you are going to support all these different platforms, you need to control your projects and libraries to maximize the benefit.  You also have the choice to change the UI for each platform, a little or a lot.  You have full control.


[source]

Comments

Popular posts from this blog

Yes, Blazor Server can scale!

Blazor new and improved Search Box

Blazor Wizard Step Component