PWAs are coming to iOS 11.3: Cupertino, we have a problem
IMPORTANT: iOS 11.3 final version is now published. Check my updated article on the topic: Progressive Web Apps on iOS are here
After the surprise yesterday from a tweet from Ricky Mondello and then the Safari 11.1 beta Release Notes stating that Web App Manifest and Service Workers are implemented which means multi-platform PWAs are now possible, it’s now time to come back to the real world and see what’s what we have.
Update 8-Feb: Beta 2 is out and the WebKit blog has published an article on how Service Workers work on its platform. This post is updated with this information.
Update 20-Feb: Beta 3 is out. This post is now updated for this version.
Update 7-Mar: Beta 4 is out. This post is now updated for this version.
Testing is not easy — better from beta 3
Testing these new additions on iOS is not straightforward because the Developer Tools on Safari won’t let you see the Service Workers on iOS yet using the Service Workers menu. However, when you connect an iOS remote inspection session, you will find two sessions with the same name, of those is the Service Worker session. It’s still a limited devtool for Service Workers but it’s a start. You will need Safari Technology Preview installed in your macOS computer for Service Worker debugging.
If you published a PWA or are about to release one, you must pay attention to the user experience and the issues you might have on iOS.
18 months ago (one and a half years already!?) I published “Don’t use iOS meta tags irresponsibly in your Progressive Web Apps.” Several companies such as Twitter and Flipkart took note at that time of these problems and remove the iOS meta tags or solved the issues (You are welcome for the free consulting ☺️).
At that time the problem was that some companies were opting in through Apple meta tags for home screen support for iOS without even testing and recognizing the differences between Android’s PWAs and iOS.
I’m sorry to confirm that most problems are the same that I stated 18 months ago, with one big difference: now you don’t need to opt-in into iOS; iOS will add support for Web App Manifest, so your PWA will be an iOS PWA automatically. But Apple didn’t mimic the same behavior as in Android which means: Cupertino, we have a problem.
A completely different Service Workers’ story
This section was added on Feb, 8th.
Apple followed the Service Worker API, but it creates an entirely different story of what it is and what we can do with it in the future. The main differences appear when Apple says:
“To keep only the stored information that is useful to the user, WebKit will remove unused service worker registrations after a period of a few weeks. Caches that do not get opened after a few weeks will also be removed. Web Applications must be resilient to any individual cache, cache entry or service worker being removed.”
That is a huge change! At Chrome, Firefox, Samsung Internet, and other browsers, a Service Worker registration is not going to be unregistered automatically, and we can rely on being there in the future. That’s why an installed PWA will be able to work offline in the future. But with Apple’s idea of a service worker, there is no guarantee that the service worker or the cache will be available in the future. It might be if the user comes back to the web app within “a few weeks.” I know, the web app should work anyway while online, but we can’t guarantee one of the key concepts of PWAs: offline access.
While it seems fair from a browser’s point of view, I don’t see it as fair for PWAs in the home screen where the user expects the app to be there.
⚠️ In Apple’s world after “a few weeks”, the PWA will just load from scratch from the server registering a new instance of a service worker and caching the files again. This is a huge deal for Progressive Web Apps, if the user installs an icon, in a few weeks it won’t be available offline and the user will end up with a full screen “there is no internet” message for the installed app.
Also, Apple’s vision limits the future of other APIs on top of Service Workers, such as Background Sync or Web Push that needs the service worker registration to stay there for a while.
There is no event or other way to know that your service worker was unregistered and that the cache storage was erased.
Also, at the same time, Apple is officially deprecating AppCache. It’s still working with a console warning. The only problem is that AppCache life cycle will stay there as the Cache Storage on other browsers, but not with Apple’s idea of the cache. So, AppCache is being deprecated and replaced with something that can not offer the same behavior.
On the bright side of the story, at least we have a definition of what to expect from a Service Worker and also about the available space to store responses in the Cache Storage. It’s going to be up to 50 MiB per partition. MiB? It’s a mebibyte, and 50 of them are around 52.5Mb. Partition? A partition is a new concept for Service Workers and it has to do with iframes. If there is no cross-domain iframes in your web app, a partition if just an origin (your domain and port). For privacy reasons, Apple went further with the Service Worker specification, and creates a new partition (some kind of a new origin) when a service worker is registered from a cross-origin iframe. That Service Worker will be responsible for requests coming from clients within the same partition (combination of top origin and frame origin) only.
I don’t think this different vision of what a Service Worker should be is new. There were several discussions in the past between the Safari team and the Chrome team (I was involved in some of them on Twitter after I published this article two years ago) and I think this is just another chapter of the same discussion. Apple wasn’t involved in the discussion of what the replacement of AppCache needs to be and here we have the result: different implementations.
Update on beta 4: This was available from beta 3, but I missed it in this post. A PWA in the home screen shares the Service Worker registration with Safari. However, it creates a different instance of it; therefore you might end up with two instances of the same service worker running at the same time. If you follow Service Workers design patterns you shouldn’t rely on global variables inside this context so it shouldn’t be a big problem.
Installed icon but online only — solved from Beta 3
Up to beta 2: If you install your PWA on the Home Screen, Service Workers are there, it’s being registered but they are not working (the SW doesn’t take the Web App as a client) so don’t expect an offline experience in this first beta. But I think this is due to a bug that should be solved in future betas.
Update 20-Feb: On beta 3 this problem was solved, so home-screen PWAs now can work offline. However, if the user is in Airplane Mode, Safari shows the OS dialog asking the user to connect to WiFi, even if all the requests were managed by the Service Worker.
PWAs: attack of the clones
Service Workers API is available on HTTPS at Safari, the Web View (that means, Chrome, Firefox, and Facebook In-App browsers), Apps added to the Home Screen (Web.app) and Safari View Controller (such as when you click on a link on Twitter on iOS).
It sounds good, right? Well, there is a significant issue here: on Safari and on each app’s Web view which means the user might end with several copies of all the files for the PWA on the same device.
Update beta 3: Safari View Controller (for example, browsing within Twitter) and home screen web apps share the same Cache Storage and Service Worker registration with Safari’s tab, but each mode gets a new Service Worker instance.
You might be thinking: Hey, Max, the same happens on Android and different browsers (Chrome, Firefox, Opera, Samsung Internet, UC Web). Well, you are right, but it’s a different use case. On Android, OS’ web views don’t have Service Workers support and PWAs on the home screen share the same SW and cache of the browser who owns that icon. Also, loading the same web apps on different browsers on the same device doesn’t seem to be a typical use case.
Now, let’s say you are an iOS user and you typically use a PWA, such as Twitter Lite. When you explicitly want to use it, you open your (pseudo)browser, such as Chrome, Edge or Firefox on iOS. You get one copy of the app. Because on iOS you can’t change the default browser if you receive a link on Mail to a tweet, Safari will open, and a second copy of the app will be “installed”. If you add it to the Home Screen as well fortunately, the same second copy of the app is there. Done? Not yet. If you use Facebook or some newspapers apps among other apps that offer you In-App browsing experiences, when you click on a link to a tweet or a Twitter account, you will have another copy per app!
So an iOS user might end with four or more copies of the same PWA per device (I’m talking about the service worker and files cached by it, not the icon). These copies might disappear after “a few weeks” if you don’t use them on that platform though.
Web App Manifest support
When there is a manifest linked in your HTML, Safari will use it instead of the old non-standard apple-mobile-* meta tags. That’s great! However, as far as of beta 1, you might also have some unexpected behaviors compared with Android.
Let’s start talking about which properties are ignored (but it’s beta 1, I don’t know which features will get there and which properties not):
- App name: only short name is used for the icon
- Theme color and background color: there are no splash screens and no colored status bar
- Icons: I saw yesterday several PWAs authors happy that their solutions were working correctly after installation on their cases, well: that’s not entirely correct. The icon is coming from the <link rel=”apple-touch-icon”> that most PWAs set, but not from the Web App Manifest. I guess that Apple will solve this in future betas and I hope it will take sizes 120x120 and 180x180.
- Orientation: no way to lock orientation
- Display: fullscreen: it works as standalone (you can still use black-translucent status bar to get fullscreen although it’s flagged as deprecated now)
- Display: minimal-ui, it works as a standard shortcut to the browser.
On the other hand, I was surprised that start_url is honored, which is a massive change from the previous Add to the Home Screen. Now Single Page Applications using pushState don’t need weird tricks when added to the home screen on iOS to start always fresh from the home. However, have in mind the URL from the manifest will be visible in the dialog.
Also, display-mode CSS media queries are working as expected.
Scope and links in standalone mode — solved in Beta 3
The Manifest’s scope makes a difference when you create a link with the <a> element. Should it open inside the PWA shell or in the browser?
Android browsers typically open URLs within the scope of the PWA context and other links in a browser or a Custom Tab. If you don’t specify the scope of the Web App Manifest, Android usually takes the folder of the manifest as the scope, which is generally the expected behavior.
Up to beta 2: Safari will not define a default scope if not specified and if that’s the case, then EVERY link in your PWA will open inside your App’s iOS window. What’s the problem? It’s iOS, and there is no back button and no back gesture, so the user might end up locked in an external website you link.
Update 20-Feb: from Beta 3 this problem was solved and now there is a default scope when no scope is defined. It was declared in the Release notes:
If you specify the scope, everything works as expected similar to Android, destinations out of the scope will open in Safari — with a back button (the small one in the status bar) to your PWA.
iOS reloads PWAs every time they get on screen
A bug (a feature?) that has been with Home Screen web apps on iOS forever is unfortunately still there. Everytime you get out of the PWA, you will lose the context, and when the user goes back, the PWA will load from scratch.
Regarding the performance, the battery usage, and the user’s perception issue that this behavior has there are much worse problems. If you link to external sites, the back button on iOS will always start the PWA from scratch which takes time, and it might not be what the user is expecting (you can trick it with local storage, but, you know, it’s not ideal).
Also, it’s a massive problem for apps with two-factor authentication, such as Twitter. If you need to go to another app to get a token or to open a text message or an email, you will get out of the PWA. When you go back to paste the code, you are out of context and, you need to start the login process again losing the validity of that code. It happened to me on Twitter! Which means, the Twitter PWA on iOS is completely unusable for me.
Other bugs — added after beta 3
- On Safari View Controller (for example, clicking on a link on Twitter), Service Workers doesn’t work after the Safari View Controller is closed and opened again.
- If you are in a full screen PWA, go to the home screen and go back to the PWA using the icon, sometimes, the PWA crashes after 1s.
- On Safari when you add a PWA to the home screen sometimes it doesn’t get the Web App Manifest and you ended up with the wrong icon that doesn’t trigger standalone mode. I’m not sure when it happens but it seems Safari is not waiting for the manifest to show the ATH dialog.
Unfortunately, there is no support for a Web App Banner or the Manifest spec’s events, such as appinstalled, so you need to find other ways to track it (you might want to use a mix of the start_url hash and navigator.standalone to do the tracking).
As expected, there is no Web Push Notification support (I know Apple, we want everything at once), even with push notification being today on the edge of the death penalty. Also, there is no Background Sync support or the Web Share API. The latest is a real shame because, from an iOS point of view, it should be straightforward to implement using the native SocialKit framework.
UX problems and bugs
As I stated in my previous article, iOS has some differences, such as:
- On iOS you don’t have a physical or logical back button or gesture. You must provide it inside the UI, always. That means you can’t use OAuth login mechanisms as a top-level document (no way to go back). Here you have an example of the Twitter Lite PWA after I clicked word”; there is no way to go back or cancel the operation. Even if I enter my email, I don’t have a way to get to the login page again.
- On iOS you can’t use transparent icons, and most PWAs are using a circular icon for Android, keeping the same for iOS where the transparent color becomes black and doesn’t seem like a good idea.
- The status bar bug that probably has five years old on iOS is still there. If you don’t state anything, in particular, the user’s status bar will just disappear no clock, no battery or wifi icon (technically, it’s black over black). The way to go over it is still to use the status-bar meta tag, now accepting white again, black, and black-translucent for a fullscreen experience (careful on iPhone X here, you might want to use the new notch-helpers on CSS). For some unknown reason, black and black-translucent are now flagged as deprecated and to be removed in the future. I guess that the theme-color on the manifest will take precedence, but why deprecating black and not white?
We still have time to make a difference
There is still room for Apple to make some changes and make our lives easier. In the meantime, there is also time for us to check upon our PWAs, such as
- Your icons: add iOS sizes and with no transparency
- If there is any <a> that will require a back button in the interface
- What to do if you are asking the user to get out of your app and come back because of the reload
- How are you promoting the installation of your app (update hints to iOS)
- How are you tracking PWA installation
Did you find anything else? Remember to follow me on Twitter as I will be updating the information frequently as well as testing on new betas in the future.