Reputation: 6911
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
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
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 :
forceReload
when they don't matchThat way any user connected or not stays up to date with the latest version.
Hope it'll help someone.
Upvotes: 6
Reputation: 8218
I found and posted the answer here, but to re-iterate:
After weeks and weeks of searching, I finally found a solution:
I add a check for versionstring on the server, and return it to the app.
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.
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