From now on, I won’t be building any more native apps. All my apps going forward will be progressive web apps. Progressive web apps are web applications which are designed to work even more seamlessly on mobile devices than native mobile apps.
What do I mean by “more seamlessly?” I mean that most web traffic comes from mobile devices, and that users install between 0–3 new apps per month, on average. That means that people aren’t spending a lot of time looking for new apps to try out in the app store, but they are spending lots of time on the web, where they might discover and use your app.
Progressive web applications start out just like any other web app, but when a user returns to the app and demonstrates through usage that they’re interested in using the app more regularly, browsers will invite the user to install the app to their home screens. PWA’s can also benefit from push notifications, like native apps.
This is where it gets interesting. Just like any native app, the progressive web app will have its own home screen icon, and when you click on it, the app will launch without the browser chrome. That means no URL bar and no web navigation UI. Just the phone’s usual status bar and your app in all its almost-full-screen glory.
This has been a long time coming. None of the technology is particularly new — with the notable exception of the emerging cross-platform standard.
In the early days of the iPhone, there was no app store. Steve Jobs wanted developers to build iPhone apps using standard web technologies.
Sometimes visionaries are spot on, but they’re 10 years ahead of their time. Looking back from 2 years ago, Steve Jobs’ recommendation to build web apps for iPhone was called his “biggest mistake” by Forbes, because native apps became a smashing success.
Looking back today, it seems obvious that he was really onto something — just way ahead of the capabilities of the existing web standards of the day.
A decade later, mobile web standards now support many of the features developers looked for with native apps, and Steve Jobs’ original vision for mobile web applications is now being pursued seriously by the rest of the world. Apple has supported “apple-mobile-web-capable” web apps that you can add to your home screen almost since the beginning using meta tags that help iOS devices find things like suitable icons.
Other vendors followed suit, each creating their own collection of meta tags to declare mobile web app capabilities, but recently, a cross-platform specification was introduced, and now, cross-platform mobile web apps are finally becoming a real thing.
The apps implementing the standard are called progressive web applications, not to be confused with confusingly similar terms like progressive enhancement or responsive apps.
Progressive web apps are just web applications designed to be mobile friendly. If the browser sees that the user wants to keep using the app, it may prompt the user to install it to their home screen, dock, etc… In order to qualify though, they have to meet a specific criteria:
- Must be HTTPS (see let’s encrypt)
- Valid manifest with required properties (Web Manifest Validator)
- Must have service worker
start_urlmust always load, even offline (using service worker)
- Must supply its own navigation
- Should be responsive to different screen sizes and orientations
Of course, using HTTPS and a service worker for offline users is just good practice for any modern app.
What many app builders seem to forget is that if you build a progressive web application, you must be able to navigate the application without the browser chrome and browser navigation gestures. The mobile devices assume that you’ve built your own navigation into the app.
For example, if you have an about page, that page must have a link back to the app UI, or the users will have to close and reopen the app to get back to your main app UI.
There’s a lot of information about building progressive web applications spread all over the web, but many of them are out of date, and lots of them contain only a fraction of what you need to know to build one. Let’s fix that.
To enable HTTPS, you’re going to need:
- A web server (I recommend DigitalOcean)
- An SSL certificate
- A strong Diffie-Hellman group (
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048)
- TLS/SSL config for your web server (instructions for Nginx on Ubuntu)
The manifest file is called
manifest.json and it’s pretty simple. It consists of the name (
short_name for the home screen icon, and an optional
name for a more complete name), a start url, and a large list of icons so you can support the large range of different icon sizes needed for various platforms. For Android + iOS, you’ll need:
- 60x60 (Apple touch icon iPhone)
- 76x76 (Apple touch icon iPad)
- 120x120 (Apple touch icon iPhone retina)
- 152x152 (Apple touch icon iPad retina)
- 180x180 (Apple touch icon for iOS 8+)
I singled out the Apple touch icons because they have the well-known names:
Where 180x180 can be replaced by whatever the specific resolution is. Using the well-known names is not required, but if you forget to include the tags, iOS can still find the icons by searching for them in your web app’s root directory if you use the well-known names.
The iOS icons don’t support transparency.
There are some features you should know about. The
theme_color sets the color of the status bar and the window header bar used when switching between apps on Android.
background_color sets the color used on the splash screen. On Android, a splash screen will be composed from the
name property (the long name), and a large icon on top of the
The first time I built a progressive web application, I was thrilled that it worked as expected on Chrome for Android, but when I looked at it in Safari/iOS, it didn’t seem to work. The reason is that mobile Safari, in spite of supporting these features using custom tags for a decade or so doesn’t yet support the web manifest spec.
So, in addition to the manifest file for supported browsers, you’ll also need special meta tags for iOS, beginning with this one, which will launch the app without the browser chrome:
<meta name="apple-mobile-web-app-capable" content="yes">
There are lots of tags to remember, though, and there may be another way to do it. There’s a web manifest polyfill that will read your manifest.json file and add the vendor-specific tags for older mobile browsers, iOS, and even Windows phone and Firefox OS.
Service Worker is a recent web platform specification that allows you to cache resources locally in order to make sure that your app still works, even if the user is not connected to the internet.
It works by hijacking your network requests and serving responses from a local cache when the user is offline. There’s a lot more to it than that, though. It’s a fairly sophisticated low-level API, which allows you to do a lot to optimize your user’s experience whether they’re online or offline.
To get started, I’m going to recommend a very simple higher-level abstraction. A little script called UpUp. Using UpUp is really simple. Here’s an example from the UpUp docs:
content-url is the URL to load when the user is offline. I just use the app’s root URL for this, and it works fine.
The assets are files that need to be cached locally in order for the app to function properly. Remember to make sure that all your images, icons, CSS, and even default AJAX request responses are included. As you can see, any file type should work.
Eventually, you may want more control over your offline resource caching than UpUp provides. When that day comes, here are some great educational resources to get you started:
Plug your device into a USB cable. Turn on USB debugging on your Android device. See remote debugging instructions. You may need to Google around to figure out how to put your Android phone in developer mode to enable remote debugging.
Once you turn on developer mode, you may see developer options show up in your settings mode. Open that and make sure that USB debugging is turned on.
chrome://inspect#devices. Hit the inspect button and you’ll get the full dev tools for your app.
chrome://inspect/#service-workers to verify that your service worker is working properly.
If you want to skip the user engagement checks and always get the install to homepage option, turn on “Bypass user engagement checks” in Chrome flags:
To test on desktop, you should also flip “Enable add to shelf”.
Progressive Web Apps now have most of the capabilities of native apps, the install friction promises to be lower than native apps, you’ll no longer need to worry about the app store gatekeepers, and you won’t have to pay anybody 30% tax on app sales for the privilege of being in an app store.
But native apps still have a few capabilities that mobile web apps will not have for a potentially long time.
Notably, most of the sensor and hardware integration specs have limited or no support in most browsers, and even basic features like the device orientation API have undergone breaking changes, with multiple versions of the spec live in various browsers, requiring some tricky logic or polyfills to use safely.
Ironically, even though Apple pioneered many of the progressive web application technologies, iOS seems to be the only major obstacle to progressive web app adoption. They don’t currently support service workers, but they are in development.
Thankfully, there’s a Cordova plugin that adds service worker support to hybrid apps on iOS.
That said, I don’t trust all web browser vendors to implement install prompts in a particularly user-friendly way. Using the spec today, users may or may not be prompted to install your app, and if they go searching for it in the app store, they won’t find it unless you also publish a hybrid app through the traditional app store process.
For the short-term, we may be stuck using Cordova or something like it to fill the gaps on iOS devices, but good support for the spec is quickly rolling out on Android devices. If you have a recent Android phone running Chrome, there’s a good chance your app will work without resorting to a Cordova build.
If you think the lack of Apple support should hold you back, remember that Android is now 86% of the global mobile OS market. It may be worth the effort to build a PWA even if you have to polyfill iOS with Cordova in order to take advantage of lower install friction for 86% of the world.
In the short term, you may still want to produce a hybrid app that can take advantage of some device APIs that are still not available using web standards.
After building my first progressive web application, I’m hopeful for the future, but I’m also conscious that it isn’t perfect. Getting everything to work smoothly across all the device platforms does take a while. You also have to remember that you’ll miss out on the discoverability features and well-known installation procedures that users are familiar with in the app stores.
Hopefully browser vendors will catch up with the vision, and eventually there will be a much better install experience for progressive web applications than there is for native apps. It looks like things are going that way.
Want to give some progressive web apps a try? Check out pwa.rocks.
If you’re about to jump into the comments to tell me how it’s impossible to build a serious app with the web platform:
This is 2016, not 2004. The web platform has come a long way. Read “10 Must See Web Apps and Games” to see what other people have been building for the web platform.
Still not convinced? Read “Why Native Apps Really are Doomed: Native Apps are Doomed pt 2”.
This article has been edited to update iOS status for service workers. It originally said that Apple had hinted at an intent to implement. The status has changed to “In Development”.