newman
newman

Reputation: 6911

My PWA web app keep showing old version after a new release on Safari (but works fine on chrome)?

I added PWA and service worker to my existing web app based on Angular 5. Everything looks fine on first release. However, when I try to release updates, something strange is happening.

On PC using Chrome, I don't have problem. After each release, I got an alert asking me to update for a new version, which is great.

However, this alert is missing on iOS, which is probably okay because iOS doesn't support auto update yet as I understand it. If I use Chrome on iOS, I can get the new version after manually refresh it (sometimes it takes a few refreshes). However, Safari browser doesn't normally show the new version. If I keeps refreshing the page, the new version comes up eventually, but it falls back again after I close and reopen it. As I play around, the only way I get to the new version is to manually clear the Safari cache first. This is not acceptable to regular user.

I understand iOS has limited support of PWA, but is this the most what we can get on iOS? Without the auto update, how can an iOS user know of the new release and update it?

Upvotes: 20

Views: 14979

Answers (3)

Manish Chauhan
Manish Chauhan

Reputation: 29

I also had the same issue and I spent days looking at it and reading about how service worker works and registers new changes. You will have to debug your service worker using https://base_web_app_url/ngsw/state . If this returns the normal state, then your service worker is working properly and will load the new changes when they are available. Sometimes, we have to close the app and reopen it so that service worker could release the old page.

If the ngsw/state is not normal then it might complain about the hash mismatch which was the case in my app. There was a post build script that was generating the new hash for styles.css and that is why the hash mismatch error, leading to SW not loading new changes.

Upvotes: -1

bossno
bossno

Reputation: 675

after trying many solutions, calling registration.update didn't make it for me. Only this one is working for me :

const forceReload = () =>
  navigator.serviceWorker
    .getRegistrations()
    .then((registrations) =>
      Promise.all(registrations.map((r) => r.unregister())),
    )
    .then(() => window.location.reload())

The strategy :

  • write a version number in the new deployed app (ie: x.x.x)
  • listen to a version number served on a webSocket
  • call forceReload when they don't match

That way any user connected or not stays up to date with the latest version.

Hope it'll help someone.

Upvotes: 6

Stephen
Stephen

Reputation: 8218

I found and posted the answer here, but to re-iterate:

After weeks and weeks of searching, I finally found a solution:

  1. I add a check for versionstring on the server, and return it to the app.

  2. I look for it in localtstorage (IndexedDB) and if I don’t find it, I add it. If I do find it, I compare versions and if there is a newer one on the server, I throw up a dialog.

  3. Dismissing this dialog (my button is labeled "update") runs window.location.reload(true) and then stores the new versionstring in localstorage

Voila! My app is updated! I can't believe it came down to something this simple, I could not find a solution anywhere. Hope this helps.

UPDATE SEPT 2019:

There were a few problems with the technique above, notably that it was bypassing the PWA service worker mechanisms and that sometimes reload would not immediately load new content (because the current SW would not release the page). I have now a new solution to this that seems to work on all platforms:

forceSWupdate () {
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.getRegistrations().then(function (registrations) {
      for (let registration of registrations) {
        registration.update()
      }
    })
  }
}

And inside my serviceworker I now throw up the dialog if there is an update, and do my location.reload(true) from there. This always results in my app being refreshed immediately (with the important caveat that I have added skipWaiting and clientsClaim directives to my registration).

This works on every platform the same, and I can programatically check for the update or wait for the service worker to do it by itself (although the times it checks vary greatly by platform, device, and other unknowable factors. Usually not more than 24 hours though.)

Upvotes: 25

Related Questions