Menu Search
Jump to the content X X
Smashing Conf New York

You know, we use ad-blockers as well. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. our upcoming SmashingConf New York, dedicated to smart front-end techniques and design patterns.

A Beginner’s Guide To Progressive Web Apps

Progressive web apps could be the next big thing for the mobile web. Originally proposed by Google in 2015, they have already attracted a lot of attention because of the relative ease of development and the almost instant wins for the application’s user experience.

Further Reading on SmashingMag: Link

A progressive web application takes advantage of the latest technologies to combine the best of web and mobile apps. Think of it as a website built using web technologies but that acts and feels like an app. Recent advancements in the browser and in the availability of service workers and in the Cache and Push APIs have enabled web developers to allow users to install web apps to their home screen, receive push notifications and even work offline.

Progressive web apps take advantage of the much larger web ecosystem, plugins and community and the relative ease of deploying and maintaining a website when compared to a native application in the respective app stores. For those of you who develop on both mobile and web, you’ll appreciate that a website can be built in less time, that an API does not need to be maintained with backwards-compatibility (all users will run the same version of your website’s code, unlike the version fragmentation of native apps) and that the app will generally be easier to deploy and maintain.

Why Progressive Web Apps? Link

A study has shown that, on average, an app loses 20%5 of its users for every step between the user’s first contact with the app and the user starting to use the app. A user must first find the app in an app store, download it, install it and then, finally, open it. When a user finds your progressive web app, they will be able to immediately start using it, eliminating the unnecessary downloading and installation stages. And when the user returns to the app, they will be prompted to install the app and upgrade to a full-screen experience.

However, a native app is definitely not all bad. Mobile applications with push notifications achieve up to three times more retention6 than their counterparts without push, and a user is three times more likely to reopen a mobile application than a website. In addition, a well-designed mobile application consumes less data and is much faster because some resources reside on the device.

A progressive web application takes advantage of a mobile app’s characteristics, resulting in improved user retention and performance, without the complications involved in maintaining a mobile application.

Use Cases Link

When should you build a progressive web app? Native is usually recommended for applications that you expect users to return to frequently, and a progressive web app is not any different. Flipkart7 uses a progressive web app for its popular e-commerce platform, Flipkart Lite, and Air Berlin8 uses a progressive web app for its online check-in process, allowing users to access their tickets without an Internet connection.

When assessing whether your next application should be a progressive web app, a website or a native mobile application, first identify your users and the most important user actions. Being “progressive,” a progressive web app works in all browsers, and the experience is enhanced whenever the user’s browser is updated with new and improved features and APIs.

Thus, there is no compromise in the user experience with a progressive web app compared to a traditional website; however, you may have to decide what functionality to support offline, and you will have to facilitate navigation (remember that in standalone mode, the user does not have access to the back button). If your website already has an application-like interface, applying the concepts of progressive web apps will only make it better.

If certain features are required for critical user actions but are not yet available due to a lack of cross-browser support9, then a native mobile application might be the better option, guaranteeing the same experience for all users.

Characteristics Of A Progressive Web App Link

Before we jump into the code, it is important to understand that progressive web apps have the following characteristics10:

  • Progressive
    By definition, a progressive web app must work on any device and enhance progressively, taking advantage of any features available on the user’s device and browser.
  • Discoverable
    Because a progressive web app is a website, it should be discoverable in search engines. This is a major advantage over native applications, which still lag behind websites in searchability.
  • Linkable
    As another characteristic inherited from websites, a well-designed website should use the URI to indicate the current state of the application. This will enable the web app to retain or reload its state when the user bookmarks or shares the app’s URL.
  • Responsive
    A progressive web app’s UI must fit the device’s form factor and screen size.
  • App-like
    A progressive web app should look like a native app and be built on the application shell model, with minimal page refreshes.
  • Connectivity-independent
    It should work in areas of low connectivity or offline (our favorite characteristic).
  • Re-engageable
    Mobile app users are more likely to reuse their apps, and progressive web apps are intended to achieve the same goals through features such as push notifications.
  • Installable
    A progressive web app can be installed on the device’s home screen, making it readily available.
  • Fresh
    When new content is published and the user is connected to the Internet, that content should be made available in the app.
  • Safe
    Because a progressive web app has a more intimate user experience and because all network requests can be intercepted through service workers, it is imperative that the app be hosted over HTTPS to prevent man-in-the-middle attacks.

Let’s Code! Link

Our first progressive web app, Sky High, will simulate an airport’s arrivals schedule. The first time the user accesses our web app, we want to show them a list of upcoming flights, retrieved from an API. If the user does not have an Internet connection and they reload the web app, we want to show them the flight schedule as it was when they last downloaded it with a connection.

Sky High screenshot11

Sky High, our fictitious progressive web app (Large preview12)

The Basics Link

The first characteristic of a progressive web app is that it must work on all devices and must enhance on devices and browsers that allow it. Therefore, we’ve built our website using traditional HTML5 and with JavaScript that simulates the retrieval of data from a mock API. Throughout the application, we are using small bits of Knockout13 to handle our Model-View-ViewModel (MVVM) bindings — a lightweight JavaScript framework that allows us to bind our JavaScript models to our HTML views. We chose to use Knockout because it is relatively simple to understand and does not clutter the code; however you may replace this with any other framework, such as React or AngularJS.

Our website follows Google’s material design14 guidelines, a set of principles that guide design and interaction. Material design not only serves as a unified standard across applications and devices, but also gives design meaning. We’ve used material design for Sky High’s arrivals view to give our progressive web app that native-app look and feel.

Finally, we tested our app to make sure it is jank-free15 and that scrolling is silky-smooth. Jank-free rendering has been shown to improve user engagement. Aim for a rendering of 60 frames per second.

For this demo, we will retrieve a static JSON file, instead of a real API. This is merely to keep things simple. In the real world, you would query an API or use WebSockets.

index.html Link

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sky-High Airport Arrivals</title>
    <link async rel="stylesheet" href="./css/style.css">
    <link href="https://fonts.googleapis.com/css?family=Roboto:300,600,300italic,600italic" rel="stylesheet" type="text/css">
</head>

<body>
    <header>
        <div class="content">
            <h3>Arrivals</h3>
        </div>
    </header>
    <div class="container">
        <div id="main" class="content">
            <ul class="arrivals-list" data-bind="foreach: arrivals">
                <li class="item">
                    <span class="title" data-bind="html: title"></span>
                    <span class="status" data-bind="html: status"></span>
                    <span class="time" data-bind="html: time"></span>
                </li>
            </ul>
        </div>
    </div>
    <script src="./js/build/vendor.min.js"></script>
    <script src="./js/build/script.min.js"></script>
</body>

</html>

The index.html file is relatively standard. We’ve created an HTML list and bound our View Model property arrivals to it using Knockout16, through the attribute data-bind="foreach: arrivals". The View Model arrivals is declared in the page.js file below and exposed in the Page module. On our HTML page, for each item in the arrivals array, we’ve bound the title, status and time properties to the HTML view.

page.js Link

(var Page = (function() {

    // declare the view model used within the page
    function ViewModel() {
        var self = this;
        self.arrivals = ko.observableArray([]);
    }

    // expose the view model through the Page module
    return {
        vm: new ViewModel(),
        hideOfflineWarning: function() {
            // enable the live data
            document.querySelector(".arrivals-list").classList.remove('loading')
            // remove the offline message
            document.getElementById("offline").remove();
            // load the live data
        },
        showOfflineWarning: function() {
            // disable the live data
            document.querySelector(".arrivals-list").classList.add('loading')
                // load html template informing the user they are offline
            var request = new XMLHttpRequest();
            request.open('GET', './offline.html', true);

            request.onload = function() {
                if (request.status === 200) {
                    // success
                    // create offline element with HTML loaded from offline.html template
                    var offlineMessageElement = document.createElement("div");
                    offlineMessageElement.setAttribute("id", "offline");
                    offlineMessageElement.innerHTML = request.responseText;
                    document.getElementById("main").appendChild(offlineMessageElement);
                } else {
                    // error retrieving file
                    console.warn('Error retrieving offline.html');
                }
            };

            request.onerror = function() {
                // network errors
                console.error('Connection error');
            };

            request.send();
        }
    }

})();

This page.js file exposes the Page module, which contains our ViewModel vm and two functions, hideOfflineWarning and showOfflineWarning. The View Model ViewModel is a simple JavaScript literal that will be used throughout the application. The property arrivals on the ViewModel is Knockout’s observableArray, which automatically binds our HTML to a JavaScript array, allowing us to push and pop items onto our array in JavaScript and automatically update the page’s HTML.

The functions hideOfflineWarning and showOfflineWarning enable the rest of our application to call these functions to update the page’s UI that displays whether we are connected online. The showOfflineWarning adds a class of loading to our arrivals-list HTML element to fade the list, and then it retrieves the HTML file offline.html through XHR. Assuming that the file has been retrieved successfully (response.status === 200), we append this to our HTML. Of course, if we aren’t using service workers17 and the user is not connected to the Internet, then it would not be possible to retrieve offline.html, and so the user would see the browser’s offline page.

The business logic from where we retrieve the data from our API and bind it to our View Models and Views is found in arrivals.js18 and is standard MVVM functionality using Knockout. In the arrivals.js file, we simply initialize the services and View Models that we will be using throughout the application, and we expose a function — Arrivals.loadData() — that retrieves the data and binds it to the view model.

Web App Manifest Link

Let’s make our web app more app-like. A web app manifest file is a simple JSON file that follows the W3C’s specification19. With it, it is possible to run the web app in full-screen mode as a standalone application, to assign an icon that will get displayed when the application is installed on the device, and to assign a theme and background color to the app. In addition, Chrome on Android will proactively suggest that the user install the web app, via a web app install banner20. To display the installation prompt, your web app needs to:

  • have a valid web app manifest file,
  • be served over HTTPS,
  • have a valid service worker registered,
  • have been visited twice, with at least five minutes between each visit.
Web app install banner21

Web app install banner (View large version22)

manifest.json Link

{
    "short_name": "Arrivals",
    "name": "Arrivals at Sky High",
    "description": "Progressive web application demonstration",
    "icons": [
        {
            "src": "launcher-icon.png",
            "sizes": "48x48",
            "type": "image/png"
        },
        {
            "src": "launcher-icon-96.png",
            "sizes": "96x96",
            "type": "image/png"
        },
        {
            "src": "launcher-icon-144.png",
            "sizes": "144x144",
            "type": "image/png"
        },
        {
            "src": "launcher-icon-192.png",
            "sizes": "192x192",
            "type": "image/png"
        },
        {
            "src": "launcher-icon-256.png",
            "sizes": "256x256",
            "type": "image/png"
        }
    ],
    "start_url": "./?utm_source=web_app_manifest",
    "display": "standalone",
    "orientation": "portrait",
    "theme_color": "#29BDBB",
    "background_color": "#29BDBB"
}

Let’s break down this manifest file:

  • short_name is a human-readable name for the application. In Chrome for Android, this is also the name accompanying the icon on the home screen.
  • name is also a human-readable name for the application and defines how the application will be listed.
  • description provides a general description of the web application.
  • icons defines an array of images of varying sizes that will serve as the application’s icon set. In Chrome for Android, the icon will be used on the splash screen, on the home screen and in the task switcher.
  • start_url is the starting URL of the application.
  • display defines the default display mode for the web application: fullscreen, standalone, minimal-ui or browser.
  • orientation defines the default orientation for the web application: portrait or landscape.
  • theme_color is the default theme color for the application. On Android, this is also used to color the status bar.
  • background_color defines the background color of the web application. In Chrome, it also defines the background color of the splash screen.
  • related_applications is not implemented in our example but is used to specify native application alternatives in the various app stores.

Add the manifest.json reference to the index.html file’s head tag:

<link rel="manifest" href="./manifest.json">

Once a user has added the web app to their home screen, they will be able to re-engage with your application immediately from their device, without having to directly open the browser. You can see how this is much more than a web bookmark.

Add to Homescreen on Chrome for Android23 from Smashing Magazine24 on Vimeo25.

Add to home screen in Chrome for Android

Service Workers

One of the more exciting aspects of progressive web apps is that they can work offline. Using service workers, it is possible to show data that was retrieved in previous sessions of the app (using IndexedDB26) or, alternatively, to show the application shell and inform the user that they are not connected to the Internet (the approach we’ve taken in this demo). Once the user reconnects, we can then retrieve the latest data from the server.

All of this is possible through service workers, which are event-driven scripts (written in JavaScript) that have access to domain-wide events, including network fetches. With them, we can cache all static resources, which could drastically reduce network requests and improve performance considerably, too.

Application Shell Link

The application shell is the minimum HTML, CSS and JavaScript required to power a user interface. A native mobile application includes the application shell as part of its distributable, whereas websites ordinarily request this over the network. Progressive web applications bridge this gap by placing the application shell’s resources and assets in the browser’s cache. In our Sky High application, we can see that our application shell consists of the top header bar, the fonts and any CSS required to render these elegantly.

To get started with service workers, we first need to create our service worker’s JavaScript file, sw.js, placed in the root directory.

sw.js Link

// Use a cacheName for cache versioning
var cacheName = 'v1:static';

// During the installation phase, you'll usually want to cache static assets.
self.addEventListener('install', function(e) {
    // Once the service worker is installed, go ahead and fetch the resources to make this work offline.
    e.waitUntil(
        caches.open(cacheName).then(function(cache) {
            return cache.addAll([
                './',
                './css/style.css',
                './js/build/script.min.js',
                './js/build/vendor.min.js',
                './css/fonts/roboto.woff',
                './offline.html'
            ]).then(function() {
                self.skipWaiting();
            });
        })
    );
});

// when the browser fetches a URL…
self.addEventListener('fetch', function(event) {
    // … either respond with the cached object or go ahead and fetch the actual URL
    event.respondWith(
        caches.match(event.request).then(function(response) {
            if (response) {
                // retrieve from cache
                return response;
            }
            // fetch as normal
            return fetch(event.request);
        })
    );
});

Let’s look more closely at our service worker. First, we are setting a cacheName variable. This is used to determine whether any changes have been made to our cached assets. For this example, we will be using a static name, meaning that our assets will not change or require updating.

self.addEventListener('install', function(e) {
    // declare which assets to cache
}

The install event fires during the installation phase of the service worker and will fire only once if the service worker is already installed. Therefore, refreshing the page will not trigger the installation phase again. During the installation phase, we are able to declare which assets will be cached. In our example above, we are caching one CSS file, two JavaScript files, our fonts file, our offline HTML template and, of course, the application root. self.skipWaiting() forces the waiting service worker to become active.

So far, we have declared our service worker, but before we see it kick into effect, we need to reference it in our JavaScript. In our application, we register it in main.js

// Register the service worker if available.
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('./sw.js').then(function(reg) {
        console.log('Successfully registered service worker', reg);
    }).catch(function(err) {
        console.warn('Error whilst registering service worker', err);
    });
}

window.addEventListener('online', function(e) {
    // Resync data with server.
    console.log("You are online");
    Page.hideOfflineWarning();
    Arrivals.loadData();
}, false);

window.addEventListener('offline', function(e) {
    // Queue up events for server.
    console.log("You are offline");
    Page.showOfflineWarning();
}, false);

// Check if the user is connected.
if (navigator.onLine) {
    Arrivals.loadData();
} else {
    // Show offline message
    Page.showOfflineWarning();
}

// Set Knockout view model bindings.
ko.applyBindings(Page.vm);

We’ve also included two event listeners to check whether the session’s state has changed from online to offline or vice versa. The event handlers then call the different functions to retrieve the data through Arrivals.loadData() and to enable or disable the offline message through Page.showOfflineWarning and Page.hideOfflineWarning, respectively. Our application also checks whether the user is currently online, using navigator.onLine27, and either retrieves the data or shows the offline warning accordingly. And in the last line of main.js, we apply the Knockout bindings to our View Model Page.vm.

If we load our application for the first time (with Chrome Developer Tools), we will see nothing new. However, upon reloading, we will see that a number of network resource have been retrieved from the service worker. This is our application shell.

Application shell28

Application shell network resources, in Chrome Developer Tools (View large version29)

Offline Test Link

A user running the application without an Internet connection (assuming that they have already been on the page) will simply result in the application shell and the offline warning being displayed — an improvement over Chrome’s prowling t-rex. Once the user has established a network connection, we disable the warning and retrieve the latest data.

Failing gracefully30

Render a custom HTML page instead of Chrome’s default page (View large version31)

The Guardian takes a particularly interesting approach when offline users access its website, providing a crossword puzzle:

The Guardian's offline crossword puzzle32

The Guardian’s offline crossword puzzle (View large version33)

Push Notifications Link

Push notifications allow users to opt in to timely updates from applications they trust, helping them to re-engage with the apps. Push notifications on the web34 allow you to engage with your audience even when the browser is closed.

Push notifications35

Push notifications on Emojoy36 (View large version37)

The Push API is supported in Chrome, Opera and Samsung’s browser and is under development in Firefox and Microsoft Edge. Unfortunately, there is no indication that the feature will be implemented in Safari.

Performance Link

One of the easiest wins with service workers is that we can improve performance with little to no effort. Comparing our website to itself before service workers were implemented, before we were retrieving over 200 KB upon page load; that is now reduced to 13 KB. On a regular 3G network, the page would have taken 3.5 seconds to load; now it takes 500 milliseconds.

These performance improvements are drastic because the application itself is very small and has limited functionality. Nevertheless, through the correct use of caching, it is possible to significantly improve performance and perceived performance, especially for users in places with low-connectivity.

Lighthouse Link

Google’s Chrome team has put together a tool for testing progressive web apps. Lighthouse38 runs in Node.js or as a Chrome plugin39 and can be found on GitHub, too.

To run a Lighthouse test, your website needs to be available online, meaning that you cannot test on localhost.

To start, download the npm package:

npm install -g GoogleChrome/lighthouse

Once that’s installed, run Chrome (version 52 onwards):

npm explore -g lighthouse -- npm run chrome
lighthouse https://incredibleweb.github.io/pwa-tutorial/

The output of the Lighthouse run will be visible in the command line and will grade your website according to the progressive web app features and properties you have implemented — for example, whether you are using a manifest.json file or whether your page is available offline.

Conclusion Link

This article is merely an appetizer for progressive web apps. We could do a lot more to create that app-like experience users are looking for, whether by supporting push notifications with the Push API40, making the app re-engageable, or using IndexedDB and background syncing41 to improve the offline experience.

Cross-Browser Support

These are still early days for progressive web apps, and cross-browser support is still limited, especially in Safari and Edge. However, Microsoft openly supports progressive web apps and should be implementing more features by the end of the year.

  • Service workers and Cache API
    Supported in Chrome, Firefox, Opera and Samsung’s browser. In development in Microsoft Edge, expected to be available by the end of 2016. Under consideration for Safari.
  • Add to home screen
    Supported in Chrome, Firefox, Opera, Android Browser and Samsung’s browser. Microsoft seems to indicate that progressive web apps will be available as store listings. No plans for Safari as of yet.
  • Push API
    Mostly supported in Chrome, Firefox, Opera and Samsung’s browser. In development in Microsoft Edge. No plans for Safari as of yet.

If more developers take advantage of the features offered by progressive web apps — which are relatively easy to implement and provide immediate rewards — then users will prefer consuming these web apps in supported browsers, hopefully convincing the other browser vendors to adapt.

Source Code Link

The entire source code for this tutorial is available in a Github repository42, and the demo is available on GitHub Pages43.

(da, al, il)

Footnotes Link

  1. 1 https://www.smashingmagazine.com/2016/09/the-building-blocks-of-progressive-web-apps/
  2. 2 https://www.smashingmagazine.com/2016/12/conversational-design-essentials-tips-for-building-a-chatbot/
  3. 3 https://www.smashingmagazine.com/2016/02/building-first-class-app-leverages-website-case-study/
  4. 4 https://www.smashingmagazine.com/2015/04/creating-web-app-in-foundation-for-apps/
  5. 5 http://blog.gaborcselle.com/2012/10/every-step-costs-you-20-of-users.html
  6. 6 http://info.localytics.com/blog/push-messaging-drives-88-more-app-launches-for-users-who-opt-in
  7. 7 http://www.flipkart.com/
  8. 8 https://flights.airberlin.com/en-DE/progressive-web-app
  9. 9 #crossBrowser
  10. 10 https://developers.google.com/web/fundamentals/getting-started/your-first-progressive-web-app/
  11. 11 https://www.smashingmagazine.com/wp-content//uploads/2016/08/sky-high-screenshot-opt.png
  12. 12 https://www.smashingmagazine.com/wp-content//uploads/2016/08/sky-high-screenshot-opt.png
  13. 13 http://knockoutjs.com/
  14. 14 https://material.google.com/
  15. 15 https://addyosmani.com/blog/making-a-site-jank-free/
  16. 16 http://knockoutjs.com/documentation/introduction.html
  17. 17 #serviceWorker
  18. 18 https://github.com/IncredibleWeb/pwa-tutorial/blob/master/demo/js/arrivals.js
  19. 19 https://w3c.github.io/manifest/
  20. 20 https://developers.google.com/web/updates/2015/03/increasing-engagement-with-app-install-banners-in-chrome-for-android
  21. 21 https://www.smashingmagazine.com/wp-content//uploads/2016/08/web-app-install-banner-opt.png
  22. 22 https://www.smashingmagazine.com/wp-content//uploads/2016/08/web-app-install-banner-opt.png
  23. 23 https://vimeo.com/177998478
  24. 24 https://vimeo.com/smashingmagazine
  25. 25 https://vimeo.com
  26. 26 https://developer.mozilla.org/en/docs/Web/API/IndexedDB_API
  27. 27 https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine/onLine
  28. 28 https://www.smashingmagazine.com/wp-content//uploads/2016/08/app-shell-opt.png
  29. 29 https://www.smashingmagazine.com/wp-content//uploads/2016/08/app-shell-opt.png
  30. 30 https://www.smashingmagazine.com/wp-content//uploads/2016/08/sky-high-offline-opt.png
  31. 31 https://www.smashingmagazine.com/wp-content//uploads/2016/08/sky-high-offline-opt.png
  32. 32 https://www.smashingmagazine.com/wp-content//uploads/2016/08/the-guardian-opt.jpg
  33. 33 https://www.smashingmagazine.com/wp-content//uploads/2016/08/the-guardian-opt.jpg
  34. 34 https://developers.google.com/web/updates/2015/03/push-notifications-on-the-open-web
  35. 35 https://www.smashingmagazine.com/wp-content//uploads/2016/08/pwa-push-opt.png
  36. 36 https://jakearchibald-gcm.appspot.com/
  37. 37 https://www.smashingmagazine.com/wp-content//uploads/2016/08/pwa-push-opt.png
  38. 38 https://github.com/GoogleChrome/lighthouse
  39. 39 https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk
  40. 40 https://developer.mozilla.org/en/docs/Web/API/Push_API
  41. 41 https://developers.google.com/web/updates/2015/12/background-sync
  42. 42 https://github.com/IncredibleWeb/pwa-tutorial
  43. 43 https://incredibleweb.github.io/pwa-tutorial/

↑ Back to top Tweet itShare on Facebook

Kevin Farrugia is a co-founder at Incredible Web, a web & mobile application development company based in Malta, EU; that delivers industry-leading solutions through constant innovation and an obsession with quality.

  1. 1

    What a shame that PWAs aren’t really feasible for Safari (which I presume includes iOS Safari) as of yet, seeing that even service workers and the Cache API are only “under consideration” – whatever that may mean.

    So it seems like Apple is really sticking to native apps for now.

    10
    • 2

      That’s because if Apple supported PWA, they couldn’t get that sweet App Store revenue and/or lock you to their ecosystem. Worse, it would encourage people to use the Web, thus giving revenue to Google.

      Which is funny, since the original version of iPhone was all web apps.

      19
    • 3

      I can see why Apple is so reluctant to jump on the pwa bandwagon. They will end up cutting into their i-tunes cash cow.

      1
  2. 4

    Obinwanne Hill

    August 11, 2016 12:21 pm

    I think Progressive Web Apps are great for existing online entities that already provide value to their audience over the Web. The ability of an existing website to detach it’s core feature set, and then make that continuously available to the end-user via very similar HTML5 code-bases is a game-changer.

    However, there needs to be a better “Add to Homescreen” affordance and completion path. I don’t have stats, but I imagine that might be less obvious for most, especially for a large user-base that associates apps with app stores. I think Google should lead the way here and do what I’ll call ‘Shadow Attribution’ i.e. allow a progressive Web app to have an ephemeral entry in the Google Play store, which then allows anyone to discover the web app and then complete the “Add to Homescreen” flow when the “app” is “downloaded”. The entry is removed whenever the app is no longer accessible.

    I also think the Service Workers interface needs to be simplified. I find the current flow a little verbose (service worker code makes up the bulk of the code in this article). Still, there might be some libraries out there that do this abstraction (and integrate the fallbacks you added for backward compatibility) so it’s probably nothing to worry about.

    All tolled, Viva La PWA! The Web…WINS!

    13
    • 5

      Ever considered changing your last name to Kenobi?

      Jk ;)

      3
      • 6

        Obinwanne Hill

        August 12, 2016 1:39 am

        The thought has crossed my mind, but I’m concerned it might come off as a bit vain. Jus’ sayin’

        7
      • 7

        Brinca means ‘play with toys’ in Portuguese.

        3
    • 8

      Adding progressive web apps as an entry to the App/Play Store would possibly impact a lot of security for all users.

      I don’t know how waterproof the current app review systems are, but PWA’s could be updated whenever the developer pleases, without any acceptance flow we see now in the app/play stores. Makes it a lot easier to add malicious code, or just simply change the app’s purpose completely…

      On a side note: I’d love to see iOS support for this, since I’m still a LOT more comfortable developing web apps than native apps…

      1
      • 9

        Obinwanne Hill

        August 14, 2016 3:58 pm

        I don’t think there would be a security issue if there’s a well thought out process behind it.

        One way they could do it is first allow existing developers who are already registered and have paid the platform fee to create a PWA id that is linked to a specific live domain, and then put this in a meta tag on the home page of the PWA. Google Play then picks it up and adds the link to Google Play store. The app then becomes discoverable via the Play store. It doesn’t appear very complicated to me.

        And, since it’s ephemeral by nature, whenever there’s something wrong with the site, then the webapp is de-listed.

        In my opinion, this would be great because a PWA could then put a ‘Download for Android/iOS’ button on their website, which would conform with existing user expectations for downloading apps to their devices.

        -1
      • 10

        Mark Caulfield

        October 13, 2016 12:24 pm

        You can already do this with ionic apps using the ionic cloud framework. This mechanism allows app developers to send code and update the app on the fly – this has been approved by Apple – as long as the new code doesn’t include any functionality that changes the main use of the app.

        3
  3. 11

    Peter McLachlan

    August 12, 2016 1:03 am

    The business case for building an app used to be about experience (mostly speed/transitions) and access to native features that weren’t available on the web. Now that app-like shopping experiences can be delivered through the mobile web, it raises the question of what, if any, role do apps now play in retail?

    I’m exploring how Progressive Web Apps work for m-commerce, and seeing initial success. If you’re interested, Mobify’s senior director of strategy put together this blog post outlining how progressive can enhance the mobile web shopping experience.

    11
  4. 12

    I don’t get a crossword puzzle for the Guardian site. I get cannot connect to the internet.

    1
  5. 13

    Thanks!

    I also LOVE web-apps because I don’t need to learn (or pay for) any ios/anadorid developing skills/tools, and keep up with my web (client/server) capabilities.

    However, ,major issues:
    1. Chrome on mobile doesn’t support “add to homescreen”, Safari does.
    2. Safari doesn’t support (as you mentioned) PUSH API
    So we are in a weird point. A little problematic.

    0
    • 14

      I believe you refer to Chrome on iPhone correct, as Chrome on Android supports “Add to Homescreen” and also uses Web App Install Banner. :)

      0
  6. 15

    I was in india last week and looking to buy Redmi Note 3 mobile one flipcart.com.
    As mobile was not often in stock i was checking on site every 1- 2 hours this PWA helped me a lot because i was on mobile data package.

    1
    • 16

      You are corr3ct. Flipkart once decided to shutdown their website and focuses only on native mobile app becuase the huge part of their revenue was coming from mobile app so they shutdowned their website. Then PWA came into existence and the engineers at Flipkart realises its power so they built Flipkart Lite – a light web version using PWA :)

      0
  7. 17

    Vwish Solution

    August 16, 2016 11:01 am

    You guys really have a good stuff of data please continue sharing with us it’s really helpful for new web designers in this competitive field.

    1
  8. 18

    Doug McDonald

    August 22, 2016 9:28 pm

    Interesting article and I see why you’ve chosen the title, however when progressive web design was first advocated, the progressive aspect focussed on providing cutting edge features with sensible fallbacks.

    As others have mentioned, many devices / browsers etc don’t have 100% support for all aspects described here. Do you have any suggestions for fallbacks in the absence of supported APIs?

    0
  9. 19

    So basically, to go all platforms with a PWA, you’ll need a PWA for Chrome/Android, a responsive regular website for Safari, and an iOS app?

    Cuts down on some developmental costs I guess…

    1
    • 20

      Yes that is correct, although the PWA and the responsive website should be the same product and the same code base (the P in PWA is progressive), and hopefully in the near future when we see new features on iOS and Safari they would be made available immediately with little development effort.

      0
  10. 21

    Isn’t the elephant in the room for Web Apps charging users for an app? The current model is fine for ‘Apps’ that supplement an underlying business, and can be given gratis but is there anything coming down the line for letting users progressively ‘buy’ a Web App?

    It would solve the iOS issue of ‘try before you buy’ for Apps and also provide more platform equivalence; at present if you want to build an app to sell, you still need to head for the App Store.

    2
  11. 22

    I am not able to make the demo app work offline. What am I missing? Here’s what I tried (on my iPhone 7):

    Open Safari
    Go to the demo link: https://incredibleweb.github.io/pwa-tutorial/
    Add the app to home screen through Safari
    Close Safari
    Switch to airplane mode
    Try launching app from home screen icon
    All I see is the Arrivals banner. The data is not showing

    Tried the same thing using Chrome on iOS. Chrome doesn’t even give me an option to Add app to home screen!

    0
  12. 23

    I have a problem loading it/getting it to show the page in my browser it says Failed to load resource: the server responded with a status of 404 /js/build/vendor.min.js not found and i downloaded it from git

    3
  13. 24

    Hi ,

    Really super cool explanation. Thanks for sharing !!!

    1
  14. 25

    Frederik Krautwald

    November 22, 2016 10:40 pm

    Loading fonts synchronously isn’t progressive.

    0
  15. 26

    im sure you can just make a browser that saves every website u ever visit for offline viewing and adds desktop icons eith full screen viewing… Probably not one that gives websites access to your phones hardware though :).

    1
  16. 27

    Can u use angularjs instead of knockout for this?

    1

↑ Back to top