What Are Progressive Web Apps, Anyway?
Users open a Progressive Web App by entering its URL in the browser. The browser then downloads the source files of the application. PWAs use a Service Worker, a central proxy, to store a copy of the source files in a local cache. When offline, the Service Worker delivers the source files from the cache, and the application continues to work. Typically, PWAs follow the Single-Page Application (SPA) pattern. This kind of application downloads all source files once and then works in-memory, i.e. view changes do not lead to roundtrips to the server. This approach makes this type of application very performant and mimics the way native apps work.
If users want faster access to the Progressive Web App, they can add it to the home screen or program list of their platform. This is when the Web App Manifest comes in. A manifest is a JSON-based file, typically named manifest.webmanifest, or manifest.json. The manifest defines the appearance of the installed Progressive Web App, its name, icon, display mode, and so on.
There are many reasons why developers would want to publish their applications in app stores:
- they have existing apps in the store with a large user base
- they expect their users to search the store to install applications
- their competitors have a store app as well
Trusted Web Activities to the Rescue
Thanks to Trusted Web Activities (TWA), developers can reuse the same PWA deployment and create a Play Store package without writing a single line of native code. In the case of TWAs, developers upload an almost empty APK to the app store. The APK only contains a link to the website that should be shown.
Backed by a library called android-browser-helper, a TWA opens a compatible browser (Chrome 72+, Edge 45.05+, Brave, Vivaldi, Fenix/Firefox Nightly). It creates a Custom Tab in which the PWA is hosted. This way, the TWA shares its state (cookies, storage) with the browser. If no compatible browser is installed, the application will not launch, but start to the default browser with the PWA’s URL instead.
The term trusted in TWA indicates that a trust relationship is required between the TWA and the website delivering the source files. Websites have to authorize the resulting APK bundle by providing its public signing key. That means developers need to upload the Digital Asset Links (a file called assetlinks.json) to the .well-known folder of the origin they want to deliver their source files from (e.g.,
https://example.com/.well-known/assetlinks.json). If the APK is not signed with the matching private key, the TWA will not launch, but the default browser will open with the given URL instead.
In the last step, the developer uploads the APK bundle into the Google Play Store where it has to meet the store’s guidelines and be approved, same as any native app. When opened for the first time, TWAs show a banner (e.g., Running in Chrome) at the bottom of the screen. Apart from that, there’s no visible difference between native applications and a TWA.
Please note that PWAs, even when shipped as a TWA, can only call web platform APIs. Fortunately, many APIs with native power have landed on the web over the past years (such as push notifications, hardware-accelerated 2D/3D visualizations, gamepad/pen/touch input, or clipboard access). Thanks to efforts like Project Fugu, the Web App Gap will continue to close in the future. However, in contrast to applications packaged with Apache Cordova (or its contender Ionic Capacitor), TWAs cannot call arbitrary native APIs.
Frictionless TWA Generation with Bubblewrap
Bubblewrap is an open-source command-line tool that simplifies TWA generation. It requires Node.js 10 or above, the Java Development Kit (JDK) 8, and the Android SDK installed on the system. Developers can install the CLI by calling
npm i -g @bubblewrap/cli on the command line. To create a new Bubblewrap project in the current directory, developers call
bubblewrap init --manifest https://example.com/manifest.webmanifest, where
--manifest points to the Web App Manifest of the PWA. Bubblewrap then downloads the manifest and launches an interactive assistant. When running for the first time, the CLI asks for the locations of the JDK and Android SDK. More information about the SDK locations on the different platforms can be found in the Bubblewrap CLI documentation.
The interactive assistant asks for different properties the resulting Android application should have, such as the application name, icons, or colors. Where applicable, the assistant suggests using the values that were defined in the PWA’s Web App Manifest. Also, the developer either needs to provide an Android Keystore (in case they already have an existing Play Store app), or create a new one. The result is a native Android app project that can also be opened in Android Studio. The project configuration is stored in the file twa-manifest.json.
To compile an APK from the project, developers run the
bubblewrap build command. As part of this process, Bubblewrap also validates the Progressive Web App by running it against the audit tool Lighthouse, which checks the correct usage of PWA features and other best practices. Also, Bubblewrap creates the assetlinks.json file that must be uploaded to the PWA’s origin, as noted above.
As the Progressive Web App updates automatically and separately, the Trusted Web Activity theoretically would not have to be touched again. In case developers need to update their TWA for some reason, they can run the
bubblewrap update command, which automatically increments the APK’s version code.
Case Study: Top-Notch Web Apps for Android 6
We recently migrated our first customer to TWA and traditionally we would have used a Cordova app. The customer wanted to replace their existing native Android application in the Play Store by their new web application. Apart from modern Android devices, the customer needs to support devices down to Android 6.0 Marshmallow. The integrated WebView of Android 6.0, which Cordova would use by default, doesn’t support all the CSS features the client’s web application requires. Crosswalk, which bundles a Chromium browser into the application package, would significantly increase the bundle size and is no longer maintained, posing a security risk to users.
Fortunately, recent versions of Chrome can be installed on this Android version, and the customer already had a working PWA. So, we generated a Trusted Web Activity from the PWA with the help of Bubblewrap. Since the CLI allows modification of the app version and offers to provide an existing Keystore, it makes it very easy to replace existing native applications in the store. There’s no visible difference between a native application and the TWA. As a result, Trusted Web Activities are also a great tool to provide modern web apps via the Play Store for legacy devices.
Our recommendation for developers is to aim for a Progressive Web App whenever possible. Using the very same codebase and easy way of deployment, developers cannot only address browsers, desktop, and mobile systems, but also app stores like Google Play, the Microsoft Store, or the Samsung Galaxy Store (currently US-only). For the Apple App Store, developers need to ship their application as a part of the application bundle, which requires wrappers like Apache Cordova or Capacitor.
In case you want your PWA to be present in the Google Play Store, Trusted Web Activities and Bubblewrap are the way to go. The process is frictionless, both for Play Store newcomers and for developers who want to replace their existing native application with a PWA. Again, the cross-platform story holds up: One codebase, maximum reach.
Thanks to André Bandarra and Ursula Brummack for reviewing this post.