Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any way yet to auto-update (or just clear the cache on) a PWA on iOS?

Tags:

I have been struggling on iOS with something that works easily on Android: Getting my PWA to auto-update when there is a new version. I am not at all sure this is even possible on iOS. I have used vue.js and Quasar to build my app, and everything works out of the box on Android. Here is the (ugly, terrible) way things stand currently on the iOS version:

  1. I can check my own server for the version and compare it against the current one stored in my app (in indexedDB) and throw up a notice that there is a new version. So far so good.
  2. Other than having the user MANUALLY CLEAR THE SAFARI CACHE (!!) there is no way I can figure out how to programmatically clear the PWA cache from within the app or force an upload in another way.

So at this point I guess my questions are:

  1. Has ANYONE been able to get a PWA on iOS (11.3 or later) to auto-update when a new version is available?
  2. Is there a way to clear the (safari) app cache from within my PWA?

Obviously it is an incredibly awful user experience to notify the user that in order to update they must perform several steps outside of the app to be able to refresh it, but it seems this is where iOS stands at the moment unless I am missing something. Has anyone anywhere made this work?

like image 443
Stephen Avatar asked Sep 07 '18 11:09

Stephen


People also ask

Does PWA automatically update?

Yes. If you don't cache it, then browser would do a regular http call - not proxied via service worker. You can even case that JS file and check for update on opening the app, refresh the app if there is a update.


2 Answers

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 as mentioned above.

  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 someone else!

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.)

like image 89
Stephen Avatar answered Sep 20 '22 14:09

Stephen


If anyone is still having issues with this, registration.update() did not work for me. I used the exact solution but when the version from my server did not match my local stored version, I had to unregister the service workers for it to work.

  if ('serviceWorker' in navigator) {
   await this.setState({ loadingMessage: 'Updating Your Experience' })
   navigator.serviceWorker.getRegistrations().then(function(registrations) {
    registrations.map(r => {
      r.unregister()
    })
   })
   await AsyncStorage.setItem('appVersion', this.state.serverAppVersion)
   window.location.reload(true)
  } 

Then when the app reloads, the service worker is reregistered and the current version of the app is visible on iOS safari browsers and 'bookmarked' PWAs.

like image 37
jbone107 Avatar answered Sep 21 '22 14:09

jbone107