Notes on install to home behaviour on iOS - locomote-sh/sw GitHub Wiki
What should happen
When a PWA is installed to a device's home screen, the following should happen:
- The service worker component remains installed and activated, and the same service worker installation is used by the installed home screen (i.e. there is no separate install + activate cycle when the PWA is installed to home);
- The data and cache already setup by the service worker (i.e. cached files + populated IndexedDB instances) should be available for use to the installed PWA.
What actually happens on iOS is:
- The service worker component is reused, as expected, but -
- The data and cache from the web browser are not reused.
This has been reported as an issue in https://bugs.webkit.org/show_bug.cgi?id=190269
This causes a major problem, as it means the PWA will probably break when the user does the following:
- Views PWA in web browser (files + data downloaded and cached by service worker whilst running);
- Saves PWA to home screen;
- Only opens PWA from home screen when a network connection is not available;
- Because data & cache haven't been carried over from the web browser, no files or data are available and PWA fails to launch.
As things stand, not a lot can be done to alleviate this problem. The bug is reportedly resolved, but developers are still reporting this as a problem in recent iOS versions (as of 2019-06-06).
Additional impact on Locomote
This buggy behaviour had an additional impact on Locomote's query API. The query API is dependent on the service worker lifecycle to ensure proper operation; specifically, query requests are only handled by the service worker after it has fully activated, activation only completing once a content refresh cycle has been completed. If a query is handled by the service worker before the first refresh then it is querying an empty or partially filled file DB, and so won't give correct results. During normal operation this is not a problem; query requests are sent to the remote server and only handled locally after the first refresh. But the iOS bug described above means that, when a PWA is first launched from the home screen, the service worker handles any query request (because it thinks it is fully activated) despite the local file DB being in a non-initialized, pre-refresh state; consequently, any query requests made immediately after the first launch of a PWA from the home screen can give incorrect results.
A workaround has been placed into the code at the following points in the code:
- https://github.com/locomote-sh/sw/blob/master/src/origin.js#L58
- https://github.com/locomote-sh/sw/blob/master/src/refresh.js#L145
Basically, the workaround involves inserting a special record with a primary key (path) of .locomote/synced
after the file DB has been refreshed.
The query code in the service worker checks for the presence of this record before executing a query, and if the record isn't found then sends the query request to the remote server instead.
This change ensures correct query results in the scenario described above, provided that a network connection is available; when a connection is not available then the query request will fail, but as outlined above, this is part of a larger problem in that case.
Splashscreen on iOS
PWA splashscreen behaviour on iOS is notoriously difficult to get working correctly, with problems occurring when splashscreens and other additional PWA meta data aren't properly specified in the page header. During testing, another additional problem seemed to be identified which prevents proper splashscreen loading. The process a user makes when adding a PWA to their home screen is:
- Select the share icon in the web browser toolbar;
- Find and tap the add to home button;
- Review and edit the PWA's name, then tap the Add button.
The third step it seems can be critical, as it appears to be at this step that iOS downloads the app icon and splashscreen image. It was noted during one test run that the app icon was slow to load and so a screenshot of the app in the browser was used instead, this suggesting that iOS only uses the specified app icon + splashscreen image if they have successfully downloaded by the time the user taps the 'Add' button. This seems to be confirmed by further testing. If the app is added quickly to the home screen (i.e. tap the Add button on the third step as soon as the dialog appears) then the splashscreen never seems to load. But if the app is added slowly - i.e. pause on the third step before tapping the Add button, then this seems to give iOS time to download the splashscreen, which then is shown when the PWA is launched.
All of this suggests a way to possibly improve the reliability of the splashscreen on iOS. Functionality can be added to the service worker client code which does the following when the page is loaded:
- Check if running on iOS;
- If yes then check which of the linked splashscreen images matches the device's display characteristics;
- If a splashscreen image is identified then create a download request for it.
The downloaded image can be discarded, the point of the operation is to ensure that the correct splashscreen image has been locally cached by the service worker so that if and when the user adds the PWA to the home screen, the image can be quickly provided to the iOS subsystem handling the save-to-home functionality, hopefully by-passing the problem described above.