Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[plugin-manifest] feature or tutorial to keep site/router state on iOS PWA between reloads #7088

Closed
datakurre opened this issue Aug 7, 2018 · 15 comments
Labels
stale? Issue that may be closed soon due to the original author not responding any more. type: question or discussion Issue discussing or asking a question about Gatsby

Comments

@datakurre
Copy link
Contributor

As iOS PWA support does not keep state between launches, gatsby-sites created with gatsb-plugin-manifest always start from the front page on iOS, making them impractical.

There's probably some obvious and easy way to save gatsby-site state into localStorage and load it later. If it is obviously easy, some tutorial would be great. I'd expect the "most difficult" thing to be reliably detect iOS PWA client so that eg. accessing the site from browser doesn't trigger this behavior.

@Chuloo Chuloo added the type: question or discussion Issue discussing or asking a question about Gatsby label Aug 7, 2018
@dbrookes
Copy link
Contributor

dbrookes commented Aug 7, 2018

I was able to get it working, here's an example.

In your Layout component - you'll need to pass location props into it from your page:

  componentDidMount() {
    const isIos = () => {
      const userAgent = window.navigator.userAgent.toLowerCase() // Detects iOS devices
      return /iphone|ipad|ipod/.test(userAgent)
    }

    const isInStandaloneMode = () =>
      "standalone" in window.navigator && window.navigator.standalone // Detects if device is in standalone mode

    if (isIos() && isInStandaloneMode()) {
      this.handleRestore()
    }
}
  handleRestore() {
    const previousLocation = localStorage.getItem("loc") || null
    const currentLocation = this.props.location.pathname
    if (
      window.history.length <= 1 &&
      previousLocation !== null &&
      previousLocation !== currentLocation
    ) {
      push(previousLocation)
    } else {
      localStorage.setItem("loc", currentLocation)
    }
  }

You can probably store and restore the scroll position the same way too although haven't checked if reach router does it the same way as react router.

@datakurre
Copy link
Contributor Author

@dbrookes Thanks. I understand that mostly, but where does that push function come?

@dbrookes
Copy link
Contributor

dbrookes commented Aug 8, 2018

It comes from gatsby-link

For a v1 site:

import { push } from "gatsby-link"

And for v2:

import { push } from "gatsby"

@datakurre
Copy link
Contributor Author

@dbrookes Thank you for your help here. I'll close this once, I have been able confirm this.

@datakurre
Copy link
Contributor Author

@dbrookes Thanks. This mostly works, but when testing, it does not always save the location and sometimes crashes “app”.

Possibly some is caused by React rendering optimizations and some by iOS bugs. I haven’t debugged further (or with Safari debugger yet).

@dbrookes
Copy link
Contributor

@datakurre it seems to be saving reliably for me, but I've only tested with iOS 11.4.1 and Gatsby v2 with react router, I haven't tried with reach router version yet but it should pass the same props. Are you sure every page you navigate to is passing location props to layout?

I have noticed it crashing sometimes when switching back rapidly, unfortunately apple doesn't let PWAs run anything in the background and it kills the process after 5 seconds or so after switching out of the app.

It seems that if you switch back into the app right before it gets killed by the OS then it kills it with it open. Hopefully apple will fix that up in iOS 12 but for now I think thats the best its going to get.

@datakurre
Copy link
Contributor Author

datakurre commented Aug 11, 2018

@dbrookes I found a reach/router -solution using its LocationProvider-hook

gatsby-browser.js:

import React from 'react';
import { LocationProvider } from '@reach/router';
import { navigate } from 'gatsby';

const isIos = () => {
  const userAgent = window.navigator.userAgent.toLowerCase();
  return /iphone|ipad|ipod/.test(userAgent);
};

// Save navigated location; Restore it on reload
const useStickyLocation = current => {
  const previous = localStorage.getItem('location') || null;
  localStorage.setItem('location', current);
  if (window.history.length <= 1 && previous !== null && previous !== current) {
    navigate(previous);
  }
};

export const wrapRootComponent = ({ Root }) => {
  const ConnectedRootComponent = () => (
    <LocationProvider>
      {({ location }) => {
        if (isIos() && isInStandaloneMode()) {
          useStickyLocation(location.pathname);
        }
        return <Root />;
      }}
    </LocationProvider>
  );
  return ConnectedRootComponent;
};

@datakurre
Copy link
Contributor Author

@dbrookes Would you think, this recipe should be included in gatsby-plugin-manifest documentation?

@dbrookes
Copy link
Contributor

@datakurre I think this would be cool as an ios-pwa plugin that gives you this retained state functionality, lets you add a viewport-fit=cover meta and adds the correct apple-touch-startup-image meta tags for launch screen images - what do you think?

Are you having any problems with reach router? I'm seeing large delays before loading some pages (especially if destination page is quite large), especially on firefox, and the back button doesn't seem to work if you've refreshed the page.

@datakurre
Copy link
Contributor Author

@dbrookes I wonder, if this is this really worth of its own plugin... I recall apple-touch-icons are planned into gatsby-plugin-manifest by many. Is "viewport-fit=cover" really always wanted feature?

I don't seem to have big pages enough to see significant delay with reach/router, but I believe I can notice some difference and I do have back/forward-button issues (browser location gets updated, but page contents not).

@dbrookes
Copy link
Contributor

You can't add apple-touch-startup-image with manifest plugin as far as I can tell, not suggesting to force any of the options, but to setup a PWA on IOS you have to configure a bunch of apple specific meta tags, most are nothing to do with manifest because iOS ignores nearly everything in it.

https://medium.com/appscope/designing-native-like-progressive-web-apps-for-ios-1b3cdda1d0e8

@datakurre
Copy link
Contributor Author

@dbrookes I agree you with apple-touch-startup-image (makes no sense in gatsby-plugin-manifest), so maybe a new plugin makes sense. Do you know if its better practice do it outside gatsby-monorepo at first or directly here?

@m-allanson
Copy link
Contributor

https://medium.com/appscope/designing-native-like-progressive-web-apps-for-ios-1b3cdda1d0e8

That was a useful article, thanks! I just posted on #7256 that the icon generation for iOS should be included in the manifest plugin. But maybe there is a case for creating a separate plugin that allows for more customisation just for iOS?

Are you having any problems with reach router? I'm seeing large delays

@dbrookes there were a series of reach router fixes last week, do you still get the delay when using the latest Gatsby v2 beta? If yes - would love if you could open an issue with a repro?

@gatsbot
Copy link

gatsbot bot commented Dec 21, 2018

Old issues will be closed after 30 days of inactivity. This issue has been quiet for 20 days and is being marked as stale. Reply here or add the label "not stale" to keep this issue open!

@gatsbot gatsbot bot added the stale? Issue that may be closed soon due to the original author not responding any more. label Dec 21, 2018
@gatsbot
Copy link

gatsbot bot commented Jan 1, 2019

This issue is being closed due to inactivity. Is this a mistake? Please re-open this issue or create a new issue.

@gatsbot gatsbot bot closed this as completed Jan 1, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale? Issue that may be closed soon due to the original author not responding any more. type: question or discussion Issue discussing or asking a question about Gatsby
Projects
None yet
Development

No branches or pull requests

4 participants