Blazor WASM PWA Cannot Change Icon, Cannot Change Name

6.5k Views Asked by At

I'm struggling with a case where I've done good research on how to it. It works for everyone but not for me!!

Environment:

  • Microsoft Windows 10 Pro
  • Visual Studio Community Edition 2019

So I've created a project and selected Progressive Web Application (PWA) from the get-go to have everything I need auto-generated. Also made the app ASP.NET Core hosted.

The startup project is Rihal.Server in standalone mode (not IIS or Docker).

When I launch the application I get the default prompt in Chrome to install app. When I click the "+" icon I get the default Blazor icon and the app's name "Rihal". So far so good. When I change the icon and name, I still keep getting the defaults! enter image description here

  1. I've tried cleaning and rebuilding all projects one by one, no errors.
  2. I've tried restarting Visual Studio.
  3. I've tried changing other things in the manifest like background color to see any change, nothing changes.
  4. I've checked the Build Action (Content). The default Copy to Output Directory is (Do Not Copy), Changing to (Copy Always) has no effect.

It's like the manifest is completely ignored.

I've developed other parts of this app and then came around to change the icon and name:

  1. Replaced the default icon (same icon used for 192 at a smaller resolution) enter image description here

  2. Updated my manifest.json for the 192 size and name/short name: (I've also tried adding multiple sizes).

{
  "name": "Rihal Timesheet",
  "short_name": "Timesheet",
  "start_url": "./",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#03173d",
  "icons": [
    {
      "src": "icon-512.png",
      "type": "image/png",
      "sizes": "512x512"
    },
    {
      "src": "icon-192.png",
      "type": "image/png",
      "sizes": "192x192"
    }
  ]
}

Other files if relevant:

Rihal.Client service-worker.js

// In development, always fetch from the network and do not enable offline support.
// This is because caching would make development more difficult (changes would not
// be reflected on the first load after each change).
self.addEventListener('fetch', () => { });

Rihal.Client service-worker.published.js

// Caution! Be sure you understand the caveats before publishing an application with
// offline support. See https://aka.ms/blazor-offline-considerations

self.importScripts('./service-worker-assets.js');
self.addEventListener('install', event => event.waitUntil(onInstall(event)));
self.addEventListener('activate', event => event.waitUntil(onActivate(event)));
self.addEventListener('fetch', event => event.respondWith(onFetch(event)));

const cacheNamePrefix = 'offline-cache-';
const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`;
const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/ ];
const offlineAssetsExclude = [ /^service-worker\.js$/ ];

async function onInstall(event) {
    console.info('Service worker: Install');

    // Fetch and cache all matching items from the assets manifest
    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));
}

async function onActivate(event) {
    console.info('Service worker: Activate');

    // Delete unused caches
    const cacheKeys = await caches.keys();
    await Promise.all(cacheKeys
        .filter(key => key.startsWith(cacheNamePrefix) && key !== cacheName)
        .map(key => caches.delete(key)));
}

async function onFetch(event) {
    let cachedResponse = null;
    if (event.request.method === 'GET') {
        // For all navigation requests, try to serve index.html from cache
        // If you need some URLs to be server-rendered, edit the following check to exclude those URLs
        const shouldServeIndexHtml = event.request.mode === 'navigate';

        const request = shouldServeIndexHtml ? 'index.html' : event.request;
        const cache = await caches.open(cacheName);
        cachedResponse = await cache.match(request);
    }

    return cachedResponse || fetch(event.request);
}

Rihal.Client csproj file

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>netstandard2.1</TargetFramework>
    <RazorLangVersion>3.0</RazorLangVersion>
    <ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <DebugType>embedded</DebugType>
    <DebugSymbols>true</DebugSymbols>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Blazor.HttpClient" Version="3.2.0-preview3.20168.3" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.0" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.0" PrivateAssets="all" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="3.2.0" PrivateAssets="all" />
    <PackageReference Include="Microsoft.Authentication.WebAssembly.Msal" Version="3.2.0" />
    <PackageReference Include="Microsoft.Extensions.Http" Version="3.1.5" />
    <PackageReference Include="System.Net.Http.Json" Version="3.2.1" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\Shared\Rihal.Shared.csproj" />
  </ItemGroup>

  <ItemGroup>
    <ServiceWorker Include="wwwroot\service-worker.js" PublishedContent="wwwroot\service-worker.published.js" />
  </ItemGroup>
</Project>
4

There are 4 best solutions below

3
On BEST ANSWER

Open the browsers debug window. Chrome or the new Edge. While it is open right click the refresh button on your page select => Empty cache and hard reload.

I found you can do this in the clients csproj file. Forcing and update in the service worker.


<Target Name="PublishServiceWorker" AfterTargets="CopyFilesToPublishDirectory">
        <WriteLinesToFile File="$(PublishDir)wwwroot\service-worker.js" Lines="/* $([System.Guid]::NewGuid()) */" />
</Target>
0
On

Create your Icon file as PNG one in 192x192 and one in 512x512 size. Name them different (I mean don't name them as they are in the default project like icon-512 and icon-912). Add these images in the wwwroot folder. Open the manifest.json file change the Icon image names to the new ones you just added and you can also change the name and shot-name values to name your application when it's installed (PWA).

1
On

So I was running into this problem in November of 2020 (VS2019 with all updates) building a new Blazor WASM PWA. I could not get the site or installed PWA to show new content reliably. I wrote a small app to modify the offline cache version in the service-worker.js. I call this app in my post build events for client and server projects. So when I publish, my cache version always gets updated and the PWAs update as I would expect.

static void Main(string[] args)
    {
        string startPoint = "const cacheName =";
        string endPoint = ";";
        string fileNameToEdit = args[0];
        string newContents = string.Empty;

        using(var sr = new StreamReader(fileNameToEdit))
        {
            newContents = sr.ReadToEnd();
            int start = newContents.IndexOf("const cacheName = ");
            int end = newContents.IndexOf(";", start) + 1;
            string stringToReplace = newContents.Substring(start, end - start);

            string newString = "const cacheName = 'cache-version-" + $"{DateTime.Now.Ticks}" + "';";

            newContents = newContents.Replace(stringToReplace, newString);

            sr.Close();
        }

        File.WriteAllText(fileNameToEdit, newContents);

        Environment.Exit(0);
    }
1
On

I think you have to increment the version of the cache anytime you want the client to download the latest files.

In your navigator, register a JavaScript file where const CACHE_VERSION = 1.01. You can increment the value whenever you want the client to updatee

https://blog.jeremylikness.com/blog/implement-progressive-web-app-hugo/