Bug 199110

Summary: PWA in iOS use old assets after publish new servicerWorker/assets
Product: WebKit Reporter: Marlon Maxwel <marlonmleite>
Component: WebKit2Assignee: youenn fablet <youennf>
Status: RESOLVED FIXED    
Severity: Critical CC: achristensen, beidson, cdumez, chrisheaththomas, etienne.maheu, hearcomestreble, ik, jorgen, nicolas, rniwa, tiago.wippel, webkit-bug-importer, webkit, w.kujawski1, youennf
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: iPhone / iPad   
OS: iOS 12   
Attachments:
Description Flags
Patch
none
Patch none

Description Marlon Maxwel 2019-06-21 10:08:39 PDT
This bug is being reported from the bug fix: https://bugs.webkit.org/show_bug.cgi?id=190269


We are currently using iOS 12.3.1 and the new changes in app/.js are publish, but the PWA in iOS load the old assets present in precache.

In Safari it works correctly, but when you're using PWA it does not work. There are behavioral differences between Safari and PWA on iOS.

Our scenario:
- Open the application in Safari;
- We installed PWA on iOS;
- We close the Safari;
- We release a new version of the application;
- PWA continues to use old asset cache - precache (apparently the serviceWorker flow in PWA is different from normal);
- PWA is obsolete and does not update to the new assets in any way;
- We reboot the Iphone and PWA works with the new assets;


This stream works properly on Chrome, Firefox, Android, Safari, but the PWA installed on iOS does not work at all.



My Expectation with PWA in IOS:
Publish a new version of my application and these changes arrive in serviceWorker so that it's possible for my app to force the app to reload to take on new modifications as the behavior it's ok in Android, Chrome, Firefox and so on.
Comment 1 Radar WebKit Bug Importer 2019-06-21 10:23:13 PDT
<rdar://problem/51992077>
Comment 2 youenn fablet 2019-06-21 10:27:50 PDT
Thanks for the report.
IIUC, the PWA is running (Safari is not) while a new version of the application is being released.
The expected behavior is for the PWA service worker to update itself and its cache assets as well. This only happens when relaunching the PWA after reboot.
If you do the same flow with Safari, the service worker and its cache assets are updated as expected.
Is that correct?

If you have a live repro case that you can share (either privately or publicly) that may help.
Comment 3 Marlon Maxwel 2019-06-21 13:41:24 PDT
(In reply to youenn fablet from comment #2)
> Thanks for the report.
> IIUC, the PWA is running (Safari is not) while a new version of the
> application is being released.
> The expected behavior is for the PWA service worker to update itself and its
> cache assets as well. This only happens when relaunching the PWA after
> reboot.
> If you do the same flow with Safari, the service worker and its cache assets
> are updated as expected.
> Is that correct?
> 
> If you have a live repro case that you can share (either privately or
> publicly) that may help.

Yes correct, in Safari the service worker and its cache assets are updated as expected.

In Android, the PWA don't require a phone reboot to apply new release/assets. This is good for user receive new released version/assets with more frequency. And this is good idea for iOS users with PWA.

I will recreate this scenario as soon as possible and publish it here. Because my app it's in homologation and not available for the public access in the moment, only in my company.
Comment 4 Etienne Maheu 2019-06-21 14:27:00 PDT
Let us continue this discussion in this thread instead.

=================================================================

> Yes, I understand this problem.
>
> The problem you mentioned that you discussed in the communiques, I also encountered these discussions but don't work.
>
> The skipWaiting function does not work on iOS equal it works correctly on all. Were you able to make updates work correctly on iOS only with skipWaiting?
>
> We applied the solution using skipWaiting combining with the worker's controllerchange to update, but it does not work in any way on iOS and so we opened the BUG I mentioned above.
>
> I would be happy to see 1 example of everything working on iOS, but using the implementations of workbox, create-react-app, vue-cli, google... none worked.

I think I understand your problem better now. What you are describing happens because iOS will never unload the PWA, so even with "skipWaiting" set, which will refresh the cache properly, the app itself never gets to restart.

Assuming that you are using the "skipWaiting" trick, you will also want to implement this code in your head html tag: https://gist.github.com/kawazoe/fa3b5a3c998d16871ffb9e2fd721cb4b

The gist contain a minified and unminified version of a script that will detect application version changes and automatically trigger a page refresh when they happen.

This code parses the content of the "service-worker.js" file that is generated by Google Workbox to look for a file called "precache-manifest.*.js". The star here correspond to a unique hash that will change every time your app updates. This script uses this hash as a site version and stores it as "pmv" in local storage. If the version is different from the version stored in localstorage, this script will refresh the page. This works because the "service-worker.js" file is requested in a way that will always bypass caches.

This is truly a hack, a workaround, to get this working on iOS. Unfortunately, it can make the app "blink" once after an update since your PWA will not wait for this call to finish before loading. Also, you will need to either reboot (if you find it to work) or clear the safari cache after you make this change to ensure that the html file that your device cached include the fix.

I am running this in production on one of my apps and it has been working fine for over 6 months now.
Comment 5 Marlon Maxwel 2019-06-24 07:00:04 PDT
(In reply to youenn fablet from comment #2)
> Thanks for the report.
> IIUC, the PWA is running (Safari is not) while a new version of the
> application is being released.
> The expected behavior is for the PWA service worker to update itself and its
> cache assets as well. This only happens when relaunching the PWA after
> reboot.
> If you do the same flow with Safari, the service worker and its cache assets
> are updated as expected.
> Is that correct?
> 
> If you have a live repro case that you can share (either privately or
> publicly) that may help.

I have made available the repository with demo and instructions for deployment and simulation of the bug.

I tested the demo code and it has the bug as reported.

See: https://github.com/marlonmleite/bug-ios-sw
Comment 6 Jan Nowak 2019-06-26 08:39:35 PDT
I have the same problem with cache in my PWA app. When new content is available app doesn't refresh even with "networkFirst" option set in workbox (I use Vue CLI with PWA add-on). Only restarting iOS makes app to refresh the cache. It was working previously but for some time it isn't. 

iOS 12.3.1, iPhone 8
Comment 7 Marlon Maxwel 2019-06-26 09:00:30 PDT
(In reply to Jan Nowak from comment #6)
> I have the same problem with cache in my PWA app. When new content is
> available app doesn't refresh even with "networkFirst" option set in workbox
> (I use Vue CLI with PWA add-on). Only restarting iOS makes app to refresh
> the cache. It was working previously but for some time it isn't. 
> 
> iOS 12.3.1, iPhone 8

While this issue isn't solved I created a workround with the solution, see more:  https://gist.github.com/kawazoe/fa3b5a3c998d16871ffb9e2fd721cb4b#gistcomment-2953706
Comment 8 ik 2021-01-28 01:23:27 PST
Any news on this? iPadOS 14.4 seems to have made this on issue in Safari, Chrome and web apps. I need to reboot to force new files to come in. My headers:

```
<filesMatch "\.(html|htm|js|css|less|json)$">
  FileETag None
  <ifModule mod_headers.c>
    Header unset ETag
    Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
    Header set Pragma "no-cache"
    Header set Expires "Wed, 3 Oct 1983 06:00:00 GMT"
    Header set Vary: *
  </ifModule>
</filesMatch>
```
Comment 9 ik 2021-01-28 06:28:26 PST
Nevermind my previous comment. I had some css that wasn't being picked up and it turns out that Safari on iPad Mini's doesn't act like it's a desktop browser.
Comment 10 Chris 2022-04-29 03:17:47 PDT
(In reply to youenn fablet from comment #2)
> Thanks for the report.
> IIUC, the PWA is running (Safari is not) while a new version of the
> application is being released.
> The expected behavior is for the PWA service worker to update itself and its
> cache assets as well. This only happens when relaunching the PWA after
> reboot.
> If you do the same flow with Safari, the service worker and its cache assets
> are updated as expected.
> Is that correct?
> 
> If you have a live repro case that you can share (either privately or
> publicly) that may help.

The PWA does not have to be "running while a new version of the application is being released" for this bug to manifest. The PWA just needs to be have been installed (added to the Homescreen). 

Without the workarounds linked by others in the comments, this bug is a blocker to deploying a PWA on iOS.
Comment 11 youenn fablet 2022-04-29 05:59:36 PDT
Created attachment 458585 [details]
Patch
Comment 12 youenn fablet 2022-05-02 07:01:38 PDT
Created attachment 458677 [details]
Patch
Comment 13 youenn fablet 2022-05-02 07:06:11 PDT
I tried reproing the issue locally and the case where things go bad is when network process is stopped between two runs of the application. In that case, the waiting service worker never gets to activating/activated and we do not update the service worker scripts.
Comment 14 EWS 2022-05-02 12:47:52 PDT
Committed r293676 (250178@main): <https://commits.webkit.org/250178@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 458677 [details].