ReactJs PWA not updating on iOS

General Tech Bugs & Fixes 2 years ago

0 1 0 0 0 tuteeHUB earn credit +10 pts

5 Star Rating 1 Rating

Posted on 16 Aug 2022, this text provides information on Bugs & Fixes related to General Tech. Please note that while accuracy is prioritized, the data presented might not be entirely correct or up-to-date. This information is offered for general knowledge and informational purposes only, and should not be considered as a substitute for professional advice.

Take Quiz To Earn Credits!

Turn Your Knowledge into Earnings.

tuteehub_quiz

Answers (1)

Post Answer
profilepic.png
manpreet Tuteehub forum best answer Best Answer 2 years ago

 

I'm building a ReactJs PWA but I'm having trouble detecting updates on iOS.

On Android everything is working great so I'm wondering if all of this is related to iOS support for PWAs or if my implementation of the service worker is not good.

Here's what I've done so far:

Build process and hosting

My app is built using webpack and hosted on AWS. Most of the files (js/css) are built with some hash in their name, generated from their content. For those which aren't (app manifest, index.html, sw.js), I made sure that AWS serves them with some Cache-Control headers preventing any cache. Everything is served over https.

Service Worker

I kept this one as simple as possible : I didn't add any cache rules except precache for my app-shell:

workbox.precaching.precacheAndRoute(self.__precacheManifest || []);

Service-worker registration

Registration of the service worker occurs in the main ReactJs App component, in the componentDidMount() lifecycle hook:

componentDidMount() {
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/sw.js')
      .then((reg) => {
        reg.onupdatefound = () => {
          this.newWorker = reg.installing;
          this.newWorker.onstatechange = () => {
            if (this.newWorker.state === 'installed') {
              if (reg.active) {
                // a version of the SW is already up and running

                /*
                  code omitted: displays a snackbar to the user to manually trigger
                  activation of the new SW. This will be done by calling skipWaiting()
                  then reloading the page
                */
              } else {
                // first service worker registration, do nothing
              }
            }
          };
        };
      });
  }
}

Service worker lifecycle management

According to the Google documentation about service workers, a new version of the service worker should be detected when navigating to an in-scope page. But as a single-page application, there is no hard navigation happening once the app has been loaded.

The workaround I found for this is to hook into react-router and listen for route changes, then manually ask the registered service worker to update itself :

const history = createBrowserHistory(); // from 'history' node package
history.listen(() => {
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker
      .getRegistration()
      .then((reg) => {

        if (!reg) {
          return null;
        }

        reg.update();
      });
  }
});

Actual behavior

Throwing a bunch of alert() everywhere in the code showed above, this is what I observe :

  1. When opening the pwa for the first time after adding it to the homescreen, the service worker is registered as expected, on Android and iOS
  2. While keeping the app opened, I deploy a new version on AWS. Navigating in the app triggers the manual update thanks to my history listener. The new version is found, installed in the background. Then my snackbar is displayed and I can trigger the switch to the new SW.
  3. Now I close the app and deploy a new version on AWS. When opening the app again :
    • On Android the update is found immediately as Android reloads the page
    • iOS does not, so I need to navigate within the app for my history listener to trigger the search for an update. When doing so, the update is found
    • After this, for both OS, my snackbar is displayed and I can trigger the switch to the new SW
  4. Now I close the app and turn off the phones. After deploying a new version, I start them again and open the app :
    • On Android, just like before, the page is reloaded which detects the update, then the snackbar is displayed, etc..
    • On iOS, I navigate within the app and my listener triggers the search for an update. But this time, the new version is never found and my onupdatefound event handler is never triggered

Reading this post on Medium from Maximiliano Firtman, it seems that iOS 12.2 has brought a new lifecycle for PWAs. According to him, when the app stays idle for a long time or during a reboot of the device, the app state is killed, as well as the page.

I'm wondering if this could be the root cause of my problem here, but I was not able to find anyone having the same trouble so far

No matter what stage you're at in your education or career, TuteeHub will help you reach the next level that you're aiming for. Simply,Choose a subject/topic and get started in self-paced practice sessions to improve your knowledge and scores.