Blog

The state of installability

How native is the web today?

You can tell your clients some good news today: they just need one, super maintainable codebase for their entire app strategy. It's called a website! But maybe call it a Progressive Web App (PWA) to your manager... 

Do you want to become a PWA master? During our one day hands-on training you'll upgrade a simple chat website into a modern installable app with offline functionality and push notifications!

Join our PWA masterclass

I have faith in the (open) web and web technology. I don't think it makes sense to create native apps in most cases, but clients generally feel they need one without actually knowing why. In order to provide insight into whether it makes sense to develop a Progressive Web App we use an app matrix to provide insight into whether an app is applicable. The whole matrix just boils down to putting functionalities next to actual usage numbers. By doing so the "feeling of needing a native app" can be justified based on facts. The outcome tells us if making a native app is a wise business decision. And let me tell you, it almost never is.

App matrix to compare feasibility across platforms
App matrix to compare feasibility across platforms

Mostly people just want certain features that are taken for granted in native apps, like home screen presence, performance, offline functionality, push notifications and last but not least store presence. All of them are perfectly possible on the web, except for that last one, store presence. It is that one feature where we had to admit that if that was super important for you a Progressive Web App maybe is not the best app strategy. But with Google, Microsoft and Samsung embracing PWA's and making them first class citizens on their OS things have changed. Let's see what we can do today!

Add to homescreen

Since day one of PWA's, installability has been one of its advertised features, but I never really got it. I fell in love with PWA's, because of the service worker and especially its power to improve performance. I never really was interested in the add to homescreen ability. Also I think the term "add to homescreen" is just weird. If you would ask people, they would say stuff like "Like a shortcut?" or "Oh, you mean installing an app?". We taught people what "installing an app" is, but "add to homescreen" definitely is something different; more like a shortcut on your phone's homescreen. It sounds like poor mans app installation.

At least this was the case when PWA's were introduced in 2015. At that time the installation was just a shortcut to a fullscreen version of your website. You could notice that when you removed the app from your homescreen and it was lacking an uninstall action:

Before WebAPK’s our Voorhoede PWA homescreen icon behaved more like a shortcut than a native app
Before WebAPK’s our Voorhoede PWA homescreen icon behaved more like a shortcut than a native app

More recently Chrome introduced automatically generating and installing a special APK of your website, referred to as WebAPK's. Which was huge, if you really think of it. The benefit of this is that your app will show up in the app launcher and it will appear in Android's app settings. Not really sexy features, but Android actually made web apps first class citizens on their OS by doing this. It paved the road towards a better install flow and a more OS integrated web app.

Our Voorhoede site as WebAPK has app info like native apps
Our Voorhoede site as WebAPK has app info like native apps

The native install banner shows up in mobile browsers when you meet certain criteria, but just like with push notifications I would like to show the banner in context and not on page load.

Also you need control to distinguish yourself from every half baked news site which will prompt you for home screen addition. Like you know, native apps.....

In order to have more control over the install flow we got the beforeinstallprompt event. Until Chrome 76, listening for that event and calling event.preventDefault() gave you the opportunity to implement your own install button, but the mini info bar would still be shown. From Chrome 76 calling preventDefault on the beforeinstallprompt event will not show the mini info bar anymore!

Add to homescreen on iOS

The beforeinstallprompt event does not work on iOS, but iOS has <meta name="apple-mobile-web-app-capable" content="yes"> and it has been supporting it already for a long time, actually as long as I can remember. Adding this meta tag will open your web app fullscreen without URL bar when added to the homescreen. It had and still has some issues, but recently Apple did fix the most annoying ones. You will not be able to prompt the user for installation, but if a user would install it to its homescreen from the menu, you can actually improve the experience by adding the correct icons and add a splash screen as described on Apple's Safari web content guide. See below the installation on iOS.

Desktop Apps

From Chrome and Edge (since January 15) we can install PWA's as desktop apps. The user can install a PWA manually from the Chrome menu, but there is no install banner that is shown when a user visits your website. We do get the beforeinstallprompt event though. And listening for that event and calling the prompt() function will show the user an install banner. Using this event we can actually integrate the installation option to our app as a feature. E.g. when a user creates an account or from a settings menu.

Store presence

So far we actually build a fullscreen experience on mobile and we have a desktop app, all without proprietary stuff. Off to the stores!

How we used to do it
If we want store presence we need a native app to some degree. So the best that we could do was to wrap our website in a native wrapper and distribute that. There are a couple of options to do so while still using web technology, like Cordova, Ionic and React Native, just to name a few. All boil down to the same approach: render your web app inside of a WebView. Just to be clear, this is not rebuilding our application with one of these frameworks. It is just a wrapper that loads our web app.

This approach has some downsides, mainly the fact that WebViews don’t share state with the browser, they add maintenance overhead and are generally less capable browsers.

This changed quite a bit with Google and Microsoft embracing PWA's and making them first class citizens on their OS's, giving us more options in how we distribute PWA's. I'll walk you through my experience getting my PWA to the Play Store, App Store and Microsoft Store.

Play store
When developing native Android applications developers can choose to open urls outside of the app in the browser or build an in-app browser using WebViews. Launching a browser is a pretty huge context switch that interrupts the user flow, while WebViews don't share state with the browser. To solve those issues Custom Tabs was introduced to give the developer more control and solve those problems. Essentially a Custom Tab opens Chrome inside a native Android package. This means for our PWA that we can give the user the same experience in a Custom Tab as within the browser. The only thing that gives away the fact that we are actually running a web app inside of the app is that URL toolbar.

Pick Up 10 running in a Custom tab.
Pick Up 10 running in a Custom tab.

That URL is not so app-like, so to get rid of that we can use Trusted Web Activities (TWA) which was introduced early 2019. It is essentially a fullscreen Custom Tab without the URL toolbar. In order to make use of TWA we need a PWA that meets the installability criteria and a Lighthouse performance score of 80/100. And of course when you distribute your app through the Play Store you need to comply with the Play Store rules. To prevent that anybody can wrap a web app into a Android app, you need to add a assetslinks.json file inside a .well-known directory in the root of your webserver. Inside of that assetslinks.json we add the sha256_cert_fingerprints property with a value that we can find inside the Google Play console. assetlinks.json looks like this:

[
  {
    “relation”: [
      “delegate_permission/common.handle_all_urls”
    ],
    “target”: {
      “namespace”: “android_app”,
      “package_name”: “com.voorhoede.pickup10”,
      “sha256_cert_fingerprints”: [
        “37:41:3A:FA:77:56:08:B6:A7:82:FC:33:7E:DC:A8:5F:EA:43:08:85:68:31:43:A5:37:43:94:88:7D:EF:C1:D3”
      ]
    }
  }
]

That' all there is to it, off to the Play Store!

Our Pick Up 10 PWA in the Play Store
Our Pick Up 10 PWA in the App Store

App store
Unfortunately on iOS there is still no way to publish your app in the App Store besides wrapping your website in a native wrapper and loading it inside of a WebView. Apple explicitly stated not accepting HTML5 apps to the App store, so what could possibly go wrong! The good news though is that coming from a JavaScript background I was able to get the app in the store relatively easy with React Native and Expo. The native code is minimal:

export default class App extends React.Component {
  onNavigationStateChange = (event) => {
    if (!isInternalUrl(event.url)) {
      this.webview.stopLoading();
      WebBrowser.openBrowserAsync(event.url);
    }
  };

  render() {
    return (
      <View style={styles.container}>
        <StatusBar barStyle=“dark-content” />
        <SafeAreaView forceInset={{ bottom: ‘never’ }}
                      style={{ flex: 1, backgroundColor: ‘#bceaf1’ }}>
          <WebView ref={webview => (this.webview = webview)}
                    source={ { uri: webviewUrl } }
                    onNavigationStateChange={this.onNavigationStateChange}
                    bounces={false}
                    renderLoading={() => <AppLoading />}
                    startInLoadingState
          />
        </SafeAreaView>
      </View>
    );
  }
}

The only "native" code I had to write was the onNavigationStateChange handler. Without this following an external link will open inside of your WebView and since there is no way to go back(as in browser back) to your web app the user will be stuck at external link. So we open the link inside of an in-app browser. And I do have to say, this navigation pattern works quite nice from a user perspective, maybe even better than the web experience. Check the app on local development below:

And voila, off to the store! Not so fast though... I ran into some trouble when publishing to the store. My app got refused because of some reasons. I'm starting to feel like a real native app developer now! First of all, my app needs access to the camera and apparently you can change the text when the native permission dialog appears and you now what, I like asking for permission in context, so I was happy to change that. Secondly my screenshots "didn't reflect the apps purpose", at least in Apple's eyes.... But you know, look at my images now, simply beautiful! And the last issue was that I linked towards another app in both the Play Store and the App Store. I must admit, it doesn't really make sense to link to the Play Store on an iOS device. I fixed this by, ahum, giving a catered experience to my end user, sometimes referred to as browser sniffing (sounds of booos fill the room). I know, I rather don't do this, but I want the web to win.

​​Pick Up 10 in the Microsoft store
​​Pick Up 10 in the Microsoft store

When Microsoft enabled Service Workers in EdgeHTML 17, they announced to start adding quality PWA's to the Microsoft Store. This paved the road to add your PWA today manually to the Microsoft Store. You need to package your PWA in a Windows app package (.appx file) and submit that to the Windows 10 store. The package contains metadata for your app and home screen icons. Submitted apps can be installed and launched from your homescreen by running a small native wrapper around your PWA. You can package your PWA into an .appx file using Visual Studio on Windows or you can use PWA builder, which also has a CLI tool. Actually I found the process of generating the package quite frustrating. I feel there are some weird bugs in PWA builder. The cli tool gives you some more info to get you app packaged, but it just silently failed on me a couple of times. But with some perseverance I was able to generate the package and submit the app to the Windows store for review. In order to submit you need a Microsoft developer account. The submission process was pretty straightforward, mostly adding textual descriptions and some icons. Off to the store! The app got accepted within a day!

After a couple of weeks I got an email telling me the app got pulled out of the store! Because it referenced other stores than the Microsoft Store, specifically the App store and Play store. Inside PWA’s installed on Microsoft 10 you get access to window.Windows, using this you can tailor your PWA for Windows usage. But we can also use this in our app to detect if we are in this Windows environment and thus not show the app banners.

Conclusion

It feels pretty good to see my single code base being used in so many different environments. I like to reach as many people as possible and now I can create three native apps in a day from my single code base. In the long run I can continue to focus on improving the user experience by investing in my web app and profit on all platforms at once, without going through the whole release cycle for the stores again. This does not only sound like a great technical architecture, but it sounds like a wise business decision! I can sell PWA's better to my clients now and you can do so too.

Let's build your next PWA together or join me in our PWA masterclass!

← All blog posts

Also in love with the web?

For us, that’s about technology and user experience. Fast, available for all, enjoyable to use. And fun to build. This is how our team bands together, adhering to the same values, to make sure we achieve a solid result for clients both large and small. Does that fit you?

Join our team