Trusted Web Activities for Android developers

Julien Bataillé
6 min readFeb 19, 2019

--

Google recently released Chrome on Android version 72, enabling Trusted Web Activities (TWAs). It was mainly reported as a way for web developers to publish PWAs to the Play Store (by Xda and this excellent article from Maximiliano Firtman).

What about native App developers? I think it’s an interesting new option to extend your native app with Web content.

Unfortunately, Google didn’t document this approach yet. You can find Chromium Blog and Web Developers site posts but nothing on Android Developers Blog.

In this post, I will share how I managed to extend a native app with a PWA resulting in a (mostly) seamless user experience.

The current state of web content in native apps

Before digging into the technical details, a quick recap of the two options we have as Android developers to expose web content into our apps:

  1. Webview: This is the most widely used component and offers a lot of flexibility. You can embed it into native views, inject cookies and bind Javascript code to Android code. On the downside, performances vary depending on Android OS version (TLDR: from Android 5.0 Lollipop it’s mostly okay) and it is not sharing state with your browser.
  2. Chrome Custom Tabs (CCT): introduced with Chrome 45, CCT offers the performances and shared cookie jar of Chrome into your app. Instead of jumping from your app to the browser, the user will see a new activity with a custom toolbar. But this customization is limited and the user will always see the URL of the content. Finally, your app doesn’t have access to any of the web state (content, cookie, storage..) displayed in a CCT.

So what’s new with TWA and why is it useful?

Where does the Trust Web Activity position itself compared to Webview and Chrome Custom Tabs? Clearly, it is an extension of the later. The main difference is TWAs run full screen, no browser UI visible. No more URL bar like with the CCT.

This can be helpful for a variety of scenarios where CCT are currently used: displaying Terms and Service, Privacy Policy and other static contents that needs to be updated across all versions of your app and available offline.

This last point is important: remember TWAs were introduced as a way to publish PWAs to the Play Store. ServiceWorkers will work as expected and the app will be able to display web content while offline.

Chromium Blog suggests another interesting use case:

An example of this is an e-commerce site where product pages are implemented in native views but the checkout flow takes place on the website.

This is a common scenario as checkout flows can be very complex, change frequently and keeping feature parity between your website and native apps can be challenge.

For this scenario to be really frictionless, you need to ensure your browser and app states are in sync: remember your native app doesn’t have any access to the web state of the content displayed in the TWA. It means you should probably use your web app for login in the first place (following good practices promoted by AppAuth SDK) or you will need to display a form to authenticate again in the TWA. To help your users login more smoothly, Chrome form autofill will be available in the TWA (one of the features not available in the WebView).

Even for a simple feature extending the capabilities of your native app, it may be a challenge to pass parameters to the web content and receiving results from the TWA. The only option so far is to use query parameters and intent URIs respectively. I’ll show a basic example of using App Links later in this article.

Show me the code

So far, Google only documented the LauncherActivity method to wrap an existing PWA and display it on app launch. It doesn’t involve much code and all the configuration is done using metadata in the manifest.

We’ll follow the same steps as in the Using Trusted Web Activities post but I’ll assume you already have a native app and you want to extend it with a TWA. Let’s get into the code.

Get the TWA Support Library

As the support library for TWA is still in development, we’ll need Jitpack for now. Add the following to you project level build.gradle:

Add the TWA Support library to your project by pointing to the latest commit, at the time of writing (2/19/2019) I got the following:

Launch the Trusted Web Activity from an existing Activity

Google documented the TrustedWebUtils class and its only public method launchAsTrustedWebActivity .

It takes 3 parameters:

  1. The context (your current activity),
  2. A CustomTabsIntent instance (see below)
  3. The URI of the PWA you want to launch as a Trusted Web Activity.

About the second parameter, the documentation states:

The given CustomTabsIntent should have a valid CustomTabsSession associated with it during construction.

It means the following simple initialization that you could use for CustomTabs will not work (I tried), it will launch as a classic CustomTab with the URL bar:

The LauncherActivity source provides a good reference implementation for the code to retrieve the required CustomTabSession instance.

First, we need to provide an implementation for the CustomTabsServiceConnection :

Next, in your activity onCreate method let’s bind this custom tabs service:

mServiceConnection = new TwaCustomTabsServiceConnection();
CustomTabsClient.bindCustomTabsService(
this, customTabsProviderPackage, mServiceConnection);

Finally, we’ll just launch the Trusted Web Activity in an onClick listener:

TrustedWebUtils.launchAsTrustedWebActivity(
MainActivity.this,
mCustomTabsIntent,
Uri.parse("https://twa-demo.firebaseapp.com/"));

Check the complete activity source code below or in the sample project on Github:

This is a very minimal implementation, in a production scenario you would want to check if Chrome is installed, updated and provide fallbacks scenarios if any of the criteria is not met.

Remove the URL bar

When running the project at this stage, the URL Bar from Custom Tabs will still show on the top of the screen. To remove it you need to associate your app and the PWA using Digital Asset Links.

You can follow the instruction from the Google Web Developers post to achieve this: https://developers.google.com/web/updates/2019/02/using-twa#remove_the_url_bar

Note: if you don’t want to use the keytool CLI, the App Link Assistant Tool in Android Studio can generate the Digital Asset Links file for you. https://developer.android.com/studio/write/app-link-indexing#associatesite

For testing purpose, I created a simple PWA with a functional ServiceWorker and published it using Firebase Hosting (thanks MPyK from Onsen UI & Monaca Team for the sample code https://medium.com/the-web-tub/build-a-pwa-using-workbox-2eda1ef51d88).

You can see the Digital Asset Links file with the fingerprint of my release certificate: https://twa-demo.firebaseapp.com/.well-known/assetlinks.json

How does it look?

You can see the result below. The native part displays a red status bar whereas the PWA is white with a blue back button.

The resulting native app launching a PWA in a Trusted Web Activity

The only way the user will notice it’s running in Chrome is the one-time pop-up message “Running in chrome”.

To navigate back from the Trusted Web Activity to the native activity, the user can hit the android back button on the bottom-left. Another option is to use an intent URI and more specifically an App Links. This is what I implemented in the top-left back button. You could use this mechanism to pass parameters back to the native activity.

Another potentially confusing user experience is when you uninstall the app:

This gives you the option to clear Chrome’s cache. If you select “Keep Data”, the website cache and permissions (including push permissions) will remain available if your user launches the PWA from the browser.

What’s next?

It’s an interesting addition to the Custom Chrome Tabs feature and I’m curious to see what developers will do with it. Even if Google documents the App/PWA relationship as one-to-one, in practice nothing stops you from linking your app with many PWA domains. You could imagine an app leveraging this to add small features or implement some kind of mini-app store within an app.

Another point I didn’t touch yet is the TrustedWebActivityService. According to the source code:

The TrustedWebActivityService lives in a client app and serves requests from a Trusted Web Activity provider (such as Google Chrome). At present it only serves requests to display notifications.

That could allow deeper integration between your native code and the TWA. I’ll make sure to update this post if I manage to get the TrustedWebActivityService to work in my sample.

--

--