React PWA Image Upload in Mobile Safari breaks application? React PWA Image Upload in Mobile Safari breaks application? reactjs reactjs

React PWA Image Upload in Mobile Safari breaks application?


We were facing almost exactly the same issue in our PWA, so first, off I want to thank you for helping us narrow down the cause.

After reviewing the iOS PWA lifecycle (article here) and a couple maddening hours of trial and error I was able to figure out a solution that is semi-acceptable.

My guess at what is happening when you leave the app mid-upload (Test #2) is that there is some internal context in how iOS handles PWA's that is not being reset, so when you go back and try to upload a file again it thinks that the upload dialog is already open.

The article mentions that opening external links without target=_blank will cause the PWA context to be deleted, so when the in-app browser closes, the PWA page reloads in the standalone window. I thought that might reset the "detached upload" context, and it ended up working.

So I created a page hosted on another domain, and linked to it below our upload button in the PWA:

// not sure the target={'_self'} is necessary but not risking it<a href={'https://externalDomain.com/reset'} target={'_self'}>    Having Issues? Reset Upload</a>

This works decently well, minus one issue. When you click this link it opens the in-app browser, but there is no "Done" button or navigation tools for the user to know how to exit. Linking back to the PWA does not work, because iOS detects that and does not reset the app context. What I did notice was that if I navigated to another page from the first external page (I originally just tested this with google.com), the "Done" button would show up, making it obvious how to exit.

With that knowledge, I guessed that you could probably just do window.history.pushState to achieve the same effect, which works. My final solution is below. It causes the entire app to reload when the user presses Done from the in-app browser, but that's far better than having them re-add to the home screen in my opinion.

const Reset: React.FC = props => {    React.useEffect(() => {        // Redirect any wayward users who find this page from outside the PWA        if (!window.matchMedia('(display-mode: standalone)').matches) {            navigate('/');        }        // push an additional page into history        const newUrl = `${window.location.href}?reset`;        window.history.pushState({ path: newUrl }, '', newUrl);    }, []);    return (        <Grid container>            <ArrowUpIcon />            <Typography variant={'h5'}>Press done above to return to App</Typography>            <Typography variant={'body1'}>Sorry for the inconvenience!</Typography>        </Grid>    );};

Hope this helps! Would love to hear if it works for you.

Edit After Production Testing: An additional important note is that your "reset" page must be on a completely different domain for this to work. Ran into this today in production, because our reset page was on a subdomain with the same root as the PWA, iOS was not resetting the entire PWA lifecycle.

SUMMARY

Key Issues:

  1. Leaving an iOS PWA while any of the "file upload" dialogs are open ('Take Photo', 'Photo Library', or 'Browse') breaks the iOS PWA lifecycle.This breakage makes it impossible for the user to open any "file upload" dialogs when clicking on a file input.
  2. In order to fix this issue, the PWA context must be completely reset.
  3. It seems that the only ways to reset the PWA context are to restart the phone, delete the app and re-add it to the home screen, or to open an external link.
  4. When opening an external link, the "Done" button that closes the iOS PWA embedded browser will not show on the initial page. The user must navigate to an additional external page in order for the "Done" button to show.
  5. External links do not trigger a reset of the PWA context reset when they have target="_blank".

Solution:

In order for the user to be able to upload files again, the PWA context must be reset. The easiest way to do this (in my opinion) is to ask them to open an external link.

  1. (In PWA): Present a link to the user to fix the fact that the upload dialog is not showing. The link destination must be a completely unrelated domain (not a subdomain) and must have target="_self" (issue #5).
  2. (External Page): Once the user clicks on the link and the external page opens, there will be no visible way to leave the page (issue #4). To resolve this, you can use history.pushState to simulate navigating to an additional page.
  3. (External Page - Bonus): To make it clear to the user that the issue has been resolved, add an arrow in the top left pointing to the "Done" button (as shown in my screenshot).