Search code examples
cachingprogressive-web-appsservice-workermanifest.jsonappicon

Update of App-Icon in installed PWA fails. How to do?


I've been trying to solve my problem for hours and am failing miserably. I have a PWA that is already installed on various devices (iPhone/Safari, Android/Chrome, Windows PC/Chrome). I use serviceWorker.js and manifest.js.

The various app icons are defined both in the manifest file and in index.php. The web console on the Windows PC does not report any errors. The PWA is installed correctly.

Now I would like to (subsequently) update the app icon with the aim of also swapping the icons on the home screen of the devices. Even if I update the file name of the app icons, the icon on the home screen no longer changes.

In the Chrome web console on the Windows PC, the new icon is displayed correctly in the manifest file. But not on the desktop or home screen.

Does anyone have any experience with this and know what to do to update the app icon?

Thank you for your support!

My serviceworker.js:

const cacheTimestamp = new Date().toISOString(); // Hier wird der aktuelle Zeitstempel in ISO-Format erstellt
const cacheName = 'my-app-cache-'+cacheTimestamp;

self.addEventListener('install', function(event) {
  self.skipWaiting();
  event.waitUntil(
    caches.open(cacheName).then(function(cache) {
      return cache.addAll([
        '/',
        'index.php'
        // Weitere Ressourcen...
      ]);
    })
  );
});

self.addEventListener('activate', function(event) {
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.filter(function(name) {
          // Überprüfe, ob der Zeitstempel älter als 14 Tage ist
          const isOldCache = name.startsWith('my-app-cache-') && name !== cacheName;
          const timestamp = name.replace('my-app-cache-', '');
          const cacheDate = new Date(timestamp);
          // const fourteenDaysAgo = new Date();
          // fourteenDaysAgo.setDate(fourteenDaysAgo.getDate() - 14);
          const tenMinutesAgo = new Date();
          tenMinutesAgo.setMinutes(tenMinutesAgo.getMinutes() - 10);
          return isOldCache && cacheDate < tenMinutesAgo;
        }).map(function(name) {
          return caches.delete(name);
        })
      );
    })
  );
  self.clients.claim();
});

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

My manifest.json

{
    "name": "Test App",
    "short_name": "Test App",
    "theme_color": "#004D7D",
    "background_color": "#004D7D",
    "display": "standalone",
    "display_override": ["fullscreen", "standalone"],
    "orientation": "portrait",
    "scope": "./",
    "start_url": "/",
    "version": "0.0.9",
    "lang": "de-DE",
    "protocol_handlers": [
        {
            "protocol": "web+testapp",
            "url": "./%s"
        }
    ],
    "icons": [
        {
          "src": "gfx/appicon-48.png",
          "sizes": "48x48",
          "type": "image/png"
        },
        {
          "src": "gfx/appicon-72.png",
          "sizes": "72x72",
          "type": "image/png"
        },
        {
          "src": "gfx/appicon-96.png",
          "sizes": "96x96",
          "type": "image/png"
        },
        {
          "src": "gfx/appicon-144.png",
          "sizes": "144x144",
          "type": "image/png"
        },
        {
          "src": "gfx/appicon-152.png",
          "sizes": "152x152",
          "type": "image/png"
        },
        {
          "src": "gfx/appicon-168.png",
          "sizes": "168x168",
          "type": "image/png"
        },
        {
          "src": "gfx/appicon-192.png",
          "sizes": "192x192",
          "type": "image/png"
        },
        {
          "src": "gfx/appicon-256.png",
          "sizes": "256x256",
          "type": "image/png"
        },
        {
          "src": "gfx/appicon-300.png",
          "sizes": "300x300",
          "type": "image/png"
        },
        {
          "src": "gfx/appicon-512.png",
          "sizes": "512x512",
          "type": "image/png"
        }
    ],
    "description": "Diese App dient nur zum Testen",
    "screenshots": [
        {
            "src": "/gfx/screenshot_portrait.png",
            "type": "image/png",
            "sizes": "375x667",
            "form_factor": "narrow"
        },
        {
            "src": "/gfx/screenshot_landscape.png",
            "type": "image/png",
            "sizes": "667x375",
            "form_factor": "wide"
        }
    ]
}

My index.php:

<!DOCTYPE html> 
<html lang="de">
<head>
<base href="/">
<!--no cache!-->
<meta http-equiv="Cache-Control" content="no-cache" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<!--WebApp-->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1,maximum-scale=1">
<meta name="apple-mobile-web-app-title" content="Test App">
<meta name="msapplication-TileColor" content="#004D7D">
<meta name="theme-color" content="#004D7D">

<!--Icons-->
<link rel='apple-touch-icon' href='gfx/appicon-48.png' sizes='48x48' id='appico48'>
<link rel='apple-touch-icon' href='gfx/appicon-72.png' sizes='72x72' id='appico72'>
<link rel='apple-touch-icon' href='gfx/appicon-96.png' sizes='96x96' id='appico96'>
<link rel='apple-touch-icon' href='gfx/appicon-144.png' sizes='144x144' id='appico144'>
<link rel='apple-touch-icon' href='gfx/appicon-152.png' sizes='152x152' id='appico152'>
<link rel='apple-touch-icon' href='gfx/appicon-168.png' sizes='168x168' id='appico168'>
<link rel='apple-touch-icon' href='gfx/appicon-192.png' sizes='192x192' id='appico192'>
<link rel='apple-touch-icon' href='gfx/appicon-256.png' sizes='256x256' id='appico256'>
<link rel='apple-touch-icon' href='gfx/appicon-300.png' sizes='300x300' id='appico300'>
<link rel='apple-touch-icon' href='gfx/appicon-512.png' sizes='512x512' id='appico512'>
<link rel="shortcut" href="gfx/appicon-152.png" sizes="152x152" id="appico152">
<link rel="image_src" type="image/png" href="gfx/appicon-300.png" id="appico300">
<link rel="icon" type="image/png" href="gfx/appicon-48.png" id="favicon"/>
<link rel="icon" href="gfx/favicon.png" type="image/png"/>

<link rel="manifest" href="manifest.json">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta content='width=device-width, initial-scale=1.0' name='viewport' />
<meta name="format-detection" content="telephone=no">
<title>Test App</title>
<meta property="og:title" content="Test App"/>
<body>
    <h1>Hallo Welt</h1>
    
    <p><button id="installButton" style="display:none;">Installiere diese App</button></p>

    <p><a href="javascript:aktualisierePWA()">Update</a></p>
    
    <script>
    if ('serviceWorker' in navigator) {
      document.getElementById('installButton').style.display = 'block';
    }
    
    const installButton = document.getElementById('installButton');
    installButton.addEventListener('click', () => {
      // Hier sollte die Installation der PWA ausgelöst werden
      alert("installation starten");
      navigator.serviceWorker.ready.then((swRegistration) => {
        return swRegistration.showNotification('App wird installiert');
      });
    });


    function aktualisierePWA() {
        alert("Update wird durchgeführt");
      if ('serviceWorker' in navigator) {
        navigator.serviceWorker.getRegistration().then(function(registration) {
          if (registration) {
            registration.unregister().then(function() {
              window.location.reload();
            });
          }
        });
      }
    }

    // Rufe die Funktion auf, um die PWA zu aktualisieren
    // aktualisierePWA();
    
    
    
    if(navigator.serviceWorker) {
        navigator.serviceWorker.register('serviceWorker.js')
          .then((registration) => {
            setInterval(() => registration.update(), 600000); // Update alle 10 Minuten (600.000 Millisekunden)
          })
        .then(
            () => {
                console.log('[SW] Service worker has been registered');
                // alert('[SW] Service worker has been registered');
                // push_updateSubscription();
                if(!('serviceWorker' in navigator)) {
                    console.warn('Service workers are not supported by this browser');
                    // alert('Service workers are not supported by this browser');
                    // alert('Service workers are not supported by this browser1');
                }
                else {
                    // alert('Service workers are supported by this browser');
                }
                if(!('PushManager' in window) || !('Notification' in window)) {
                    console.warn('Push notifications are not supported by this browser');
                    // alert('Push notifications are not supported by this browser');
                    // alert('Push notifications are not supported by this browser2');
                }
                else {
                    // alert('Push notifications are supported by this browser');
                }
                if(!ServiceWorkerRegistration || !('showNotification' in ServiceWorkerRegistration.prototype)) {
                    console.warn('Notifications are not supported by this browser');
                    // alert('Notifications are not supported by this browser3');
                }
            },
            e => {
                console.error('[SW] Service worker registration failed', e);
                // changePushButtonState('incompatible');
            }
        );
    }
    </script>
</body>
</html>

I also tried to link the Icons with a Cache-Busting "appicon.png?v=2".

But everything I did failed. The App-Icon is not updating.


Solution

  • According to an article from 4 years ago (https://web.dev/articles/manifest-updates), it seems that updating icons on desktop or Android Chrome is not supported yet.

    You can find the related Chromium issue here: https://issues.chromium.org/issues/40181505.