PWAs on iOS 12.2 beta: the good, the bad, and the “not sure yet if good”
A year ago, in January 2018, Apple surprised everyone with its early support for Progressive Web App technologies in iOS 11.3 beta. At that time, I published PWAs coming to iOS: Cupertino, we have a problem. Two months later, the stable release appeared and most of the bugs and UX issues remained during 2018, with new bugs coming in and out between iOS 11.4 and 12.1.
Note: Final iOS 12.2 was released, here is the updated article: https://medium.com/@firt/whats-new-on-ios-12-2-for-progressive-web-apps-75c348f8e945
Exactly one year after the first beta of iOS 11.3, Apple released last week the first beta of iOS 12.2: the first version since PWA support that responds to all the critics by offering solutions to the two biggest problems on PWAs on iOS. So yes, they took a whole year to say “we are working on this.” But wait, not so fast, I’m not saying yet that the solution is a good one. Let’s see 😬.
👍 The good
Let’s start with the good news.
There are new additions that are welcome to the PWA world, including:
- Gestures now available for navigation within your PWA (aka back gesture)
- Web Share
- Intersection Observer
- <datalist> support
- <input type=color> support
- inputmode attribute support
- Abortable Fetch
- CSS Conic Gradients
- Changes in app’s lifecycle and external links management
- New experiments available (but disabled by default): Pointer Events, CSS Custom Properties, CSSOM View Scrolling, CSS Painting, CSS Typed OM, MediaCapabilities, Media Recorder, Server Timing, Web Authentication, WebGL 2.0, changes to WebRTC
- New experiments available and enabled by default: every <a> without a target will imply a rel=noopener, IntersectionObserver, VP8 codec and H264 simulcast for WebRTC
- Preload, Storage Access, Service Worker and the Cache Storage APIs are not an experiment anymore and they can’t be disabled now
Let’s see in details some of these additions
Progressive Web Apps now have the navigation gestures enabled, similar to Safari. It works for every URL within your scope, including client-side routes and it’s mostly useful for the back action as there is no back button on the screen while in standalone mode.
Web Share Level 1 is now supported on all the Web platforms, including Safari, standalone PWA, WebView (such as Facebook Mobile Browser or Chrome on iOS) and Safari View Controller (such as a link opened within the Twitter native app)
The first addition is the new color picker using the same space as the keyboard
The second addition is support for <datalist> that looks very similar to a <select> but only when clicking on the little arrow at the right. The arrow appears when there are suggestions available, such as when the input is empty or when you start typing and there are options with that substring. The suggested options also appear on the keyboard for fast selection.
And the third change is the support for inputmode, an attribute that can be applied to <input>, <textarea> and any element with contenteditable, so now you can specify different keyboards for those cases.
Changes in lifecycle and external links management
I would like to see this in “The good” section but unfortunately, you will have to wait for a bit longer in this article for the “The not sure if good yet” section regarding lifecycle and external links management.
👎 The bad
On the bad side, standalone PWAs are still powered by the weird Web.app process and its sibling WebApp1.app. That means it’s not 100% Safari or SFViewController so it has its own bugs and issues. For example, this means PWAs can’t still make use of WebRTC or the camera stream as there is a bug that has been there for years now. Therefore PWAs that need to open the camera, such as QR Code readers can only take snapshots.
Support for the Web App Manifest spec is still poor and undocumented. The implementation doesn’t make any use of the manifest for:
- Icons — I actually agree with Apple on this as most icons are not iOS-optimized, but the latest version of the spec has a solution for that.
- Orientation or display: fullscreen
- Splash screens
- Theme-color and background-color
- Events: appinstalled or beforeinstallprompt (the one that let us create a custom installation dialog trigger) are not triggered
Many of the expected APIs and behavior compared with other browsers are still not supported, such as:
- Web Push
- Background Sync
- Page Lifecycle
- Service Workers on WebViews (so no PWAs on Chrome or Facebook)
- Universal Links / Link Capturing
Bugs, but it’s only beta 2
There are some things that are not working fine that I expect to be solved in future betas, such as:
- PWAs running in standalone mode are not inspectable or debuggable using Safari or Safari TP anymore, only within Safari
- Web Authentication is available as an experiment, but even when enabled I couldn’t make it work. Same for other experiments, such as MediaRecorder
- Page Visibility events are not fired on PWAs while in standalone mode. That will be a huge problem if not solved.
🤔 The not sure if good yet
I will separate this section into two parts: 1) behavior and API changes, and 2) promises of a better architecture for PWAs.
Behavior and API changes
I see a couple of changes that might affect your app, including:
- Accessing sensor APIs is now disabled by default, so no accelerometer, gyroscope or magnetometer APIs will work on websites unless the user enables a Settings option under “Safari.” Update: details on the story of why Apple is doing it can be found in this discussion and this Wired article. Chris Dumez from the WebKit team confirmed there will be no permission request API at this point, but they are discussing an API for it.
- WebSQL might be disabled by default. There is a new Experiment “Disable WebSQL” that is enabled by default on the latest Safari TP on macOS, but disabled on this beta of iOS.
- Non-HTTPS websites are now marked as “Not secure” following Chrome and other browsers.
- SPDY support was marked as obsolete and it will be removed in future versions; that shouldn’t a big deal if you already upgraded to HTTP/2.
Promise 1: App’s Lifecycle and the reload problem
One of the worst issues for PWAs on iOS -if not the worst- is the reload problem. Every time you get out of a PWA, the instance is terminated, so if you go back to it, it restarts from scratch. That was making many PWAs unusable on iPhones and iPads, such as Starbucks, Uber and even Twitter on some situations, such as OAuth logins on different origins or with two-factor authentication.
Apple seemed to take note of the issue and in this release: there is a new lifecycle. But I’m sorry to say, it’s still buggy and weird. Mostly when you compare it with the native app's behavior.
While it’s not completely clear how it works, based on a couple of hours of testing this is my conclusion:
- Every PWA icon has its own saved context, so two icons from the same PWA won’t share their context. Each icon will keep its internal state. If you open one and immediately another one, the first one will use Web and the second one WebApp1.
- If you close the screen of your PWA from the multitask mode (killing it), it doesn’t delete the saved state. So if you open the PWA again from the icon, it will continue as its previous state. That means there is no way to reload the app or start it from scratch from the beginning from a user action.
- If you go back to the app using multitask, a gesture or tapping on the home screen’s icon again, the PWA engine process starts from scratch but quickly restores your PWA state if available. So it’s not completely available as soon you go back as a native, but it’s much faster than starting it from scratch. On an iPhone X, there is approximately a one-second context load delay when you go back.
- After a couple of minutes, the saved context seems to disappear. So if you get out of the PWA, do nothing with your phone and wait 15 minutes to go back to the PWA, it restarts from scratch.
- While the Web and Web1 processes seem to disappear from memory when you get out of the app, the saved context is shared with the rest of the OS memory. That means, if you get out of the PWA and you open a high-memory consuming native app, the saved contexts for all the PWAs might disappear and when you go back to the PWA, even after 20 seconds, your PWA might start from scratch as in iOS 12.1, as with native apps.
- Update Beta 2: sometimes, when you go back to an app with a saved state, the canvas is completely white and nothing is rendered on screen.
- When you got out of the app, the OS still shows the launch image instead of a screenshot of the last moment you used the app. And if you don’t provide a launch image -as most PWAs unfortunately- you just see a white screen.
So, as of today, PWAs are saving state between sessions, not reloading the whole context unless:
- Some unspecific time has passed
- You restart the device
- The device is low in available memory when you open other native apps
While Apple trying to find a solution is a piece of good news, I see two big issues with the current implementation:
- No events to detect lifecycle changes: Page Visibility event is not fired (visibilitychange) and Page Lifecycle API is not implemented (freeze and resume events), so there is no actual way to know when your app loses active state and when you resume. This is particularly a big problem for gaming and multimedia apps.
- Closing the app from the multitasking mode (such as dragging it out of the screen), doesn’t make the app to start from scratch as the user will expect.
- Because you can’t restart the app, if you are stuck in some problem you can’t get out. For example, in beta 1 if your PWA is playing a video and you go to the home, when you go back, the video continues playing but you only hear the audio and the content is not working anymore.
Promise 2: Handling external links from your PWA, aka let’s use OAuth on iOS as well
Up to iOS 12.1, every link pointing to a destination outside of the manifest’s scope opens in Safari by default. From iOS 12.2 beta 1, an In-app browser is used. Therefore, all your links now open within your own app’s scope and they have a “Done” button to go back to your app. Every navigation that you make on that window will happen there. Back gesture is enabled on this browser (dragging from the edge to the right).
It’s a similar idea to the one used by Chrome on Android. In this case, the In-App browser is not WebView-based (for example, it supports Service Workers), it seems a special mode of SafariVC.
When the external URL redirects or points to a URL within the scope, the In-App browser closes and loads the content in the standalone app, coming back to the app. This is particularly useful for OAuth authentication. The In-App browser shares storage context with the opener PWA, so you can use URLs outside of the scope but within the same origin to share data.
What’s the problem? Why didn’t I add this into “The Good” yet?
The are some bugs in this beta, such as
- Sometimes, the “Done” button is not there so there is no actual way to get out of the external link. Not even closing the app (see the previous section)
- If you close the external link and open another link the whole app stops working: you can see it, you can scroll but no interaction is now working: no click, no typing, nothing
UPDATE Beta 2: this bug was solved, the app continues after you close the in-app browser.
- When you click “Done” for a second you will see the external link rendered in the window of your standalone app
The problem is not the bugs, but the current experience. Compared with Safari View Controller or how Chrome on Android manages the same situation (next image) we have the following restrictions on the current implementation:
- No UI customization, such as using the theme-color
- No way to see the full URL, only the domain
- No visual way to navigate: back button, reload, etc.
- No way to check TLS/SSL certificate to avoid phishing attacks
- No way to move the navigation to Safari
- No way to share the URL
- Every new link you click on that In-App Browser may or may not create other instance of the browser with its own “Done” button that will go to a stack (no visual clue that it’s happening). It seems to be based on the origin. If you click on the same origin link it uses the same In-App Browser instance; if not, a new one. There is never a back button, so links within the same origin can be navigated back only with the back “peek” gesture. If you navigate in 10 links to different hosts, you need to click “Done” 10 times to go back to the original PWA.
- Links to other protocols are not working, such as tel:, sms:, skype:
For OAuth, this change is great, but for linking to other websites the thing that you can’t get to the browser might be a problem. For example, if you install AppScope, you can’t actually be able to install any PWA from there.
Waiting for next betas
It’s good to see Apple finally took the responsibility of solving issues for PWAs. It’s incredible they took a whole year to answer to the community. Solutions offered in this beta are still not good enough, so I really hope they will listen on time now before releasing this to the public.
Also, if you find bugs you can submit a report to https://bugreport.apple.com/
Did you find any other bugs or other new feature or ability?