Google Play Store now open for Progressive Web Apps 😱

Maximiliano Firtman
Jan 31 · 19 min read
Disclaimer: I’m not affiliated with Google Play, Chrome or any other company mentioned. This is not an official statement; usage of the logo and name is just for illustration.

Chrome 72 for Android shipped the long-awaited Trusted Web Activity feature, which means we can now distribute PWAs in the Google Play Store! I played with the feature for a while, digging into the APIs and here you have a summary of what’s going on, what to expect and how to use it today.

This article is an introduction and I’m working in a tutorial series, so if you are interested in that, follow me on Twitter or subscribe to my newsletter.

PWAs can now play in the Store

Let me start saying that the publishing process is not straightforward as it should be (such as “enter your URL” in the Play Console and it’s done.) It’s also not a way to use the currently available WebAPK and publish it in the store. It’s a Java API that communicates through services with Chrome and seem to be in the early stages, so there is a lot of manual work to do yet today.

I see this as the first step and I’m sure better tooling will appear soon (maybe from the community) using these now available APIs to create a one-click to store mechanism. But with the current API, it’s possible to ship a PWA’s launcher. I will share my experience in this article for everyone interested.

For some reason, the feature doesn’t appear as shipped yet in Chrome Platform Status and there is still no updated documentation available more than the one published 15 months ago.

*UPDATE 2/5: The Chromium Blog posted a short post confirming TWAs and with some technical confirmations of this article.

*UPDATE 2/1: Paul Kinlan, Lead of Chrome DevRel @ Google confirmed TWA was shipped and docs are just delayed; the reason for the delayed official notification and docs is that the go/no-go for the feature on Chrome 72 was a last-minute decision.

Here you can watch a video of Pete Le Page explaining TWAs a year ago.

Why publishing a PWA in the store?

Well, it’s a long discussion, but I’ve been doing consulting with small and big companies for years, and when talking about PWA investment, the store is a recurrent demand. “My users will look for my app in the Store”, “I already have a native app that I want to stop doing, but I don’t want to lose my users”, “I need to access a native API”, or “I want to monetize my PWA.”

From now, publishing your PWA in the Store -as well as from the browser- will be possible. Of course, it’s an opt-in operation. The Play Store is not emulating the Microsoft Store: your PWA won’t be listed in the store if you don’t compile your own APK, and publish it.

Advantages over standard PWA installation

  • Offer a Home Screen Widget
  • Offer App Shortcuts (when you long press the app’s icon) and other deep integrations with the OS
  • Offer a wear OS companion app or Android Auto extension
  • Be re-installed after a hard reset or a backup restore on a new phone
  • Have background services accessing native features (communication with the PWA is still limited — more on this later)
  • Monetize the App — limited today, more on this later
  • Have some native screens mixed with PWA content
  • Distribute more than one PWA icon in the Launcher and/or home screen pointing to different URLs (within the same host)
  • Better internationalization support

What’s new here?

There were already some PWAs in the Store, but now they will be much easier to produce and publish

In Google Play Store there are already some PWAs published such as Google Maps Go, Instagram Lite or Twitter Lite. The first one is using some kind of a private pre-TWA version, and the last two are using a WebView that while not ideal, it was the only way to do something like this before TWAs. These apps are adding a lot of native code for some things such as notifications. We want to publish PWAs as web developers, we don’t want to write a lot of Java code.

TWA is a special mode on Chrome Custom Tabs, a solution available to native Android apps from Chrome 45 to open an In-App browser.

Is TWA a Hybrid framework, similar to Cordova?

This is how a PWA looks like with Trusted Web Activity (Starbucks actually didn’t have one yet). I don’t see the theme-color implemented yet

With Trusted Web Activity you don’t need to package any resource file from your PWA (only native components, in case you want them); all your resources will be downloaded and updated on the fly from your Service Worker. Your PWA will still be rendered with the installed Chrome version, sharing all storage, cache, and sessions with the browser. Therefore, if your user has a session on your website opened when the user installs the app from the Play Store, she will still be logged in. The user is just installing a shortcut to Chrome using a special mode.

Play Store approval requirements (*UPDATE 2/5)

  • Passing the PWA Criteria (typically today: HTTPS, a Service Worker with a fetch event handler, and a Web App Manifest with a 512px icon, a background_color, and basic other properties set.)
  • Performance Score with a minimum of 80/100, tested with Lighthouse (available in Chrome Dev Tools, or as an NPM CLI.)
  • All current Google Play Store rules.

As per the Chromium Blog post, published a few days after this article was first published, “Apps which fail to meet TWA quality requirements or Play store policy may be denied entry or delisted.”

I’m not completely sure yet if these requirements will be checked by the Play Store QA team when publishing the app or not.

Security Model of PWAs in the Google Play Store (*UPDATE 2/4)

Also, when the user uninstalls the app from the Application’s Manager, we will get a warning stating that app’s state and data is still available while in Chrome, so she should clear cache as well if needed. That includes, for example, the Web Push permission, so even if the user uninstalls the app, the app can still send push notification messages. The message was spotted by Henry Lim:

These dialogs and the reason for them were confirmed by Paul Kinlan, from the Chrome team.

Development options

We can develop apps with TWA:

  • Using a high-level Java Support Library provided by the Chrome team: in this case, you don’t need to write any Java or Kotlin native code; you create an Android Studio project (or clone the example), set up some metadata in AndroidManifest.xml from your Web App Manifest and you are done.
    The framework will provide the connection with TWA and optional abilities to create a Settings entry in the Android device and to make Web Push notifications available. The framework is currently available as a support library in a temporary Jitpack repository. I guess that’s not going to be the final location for this library in the future.
  • Using the Trusted Web Activity manually. If you have experience developing Android apps with Java or Kotlin, you can just plug your PWA manually into your app. That means you can have some native activities and at one point you can open the Trusted Web Activity with your PWA. In this case, I suggest analyzing the Support Library to understand how to connect to Chrome from your project.

*UPDATE 2/5: There is now available documentation in the Android website regarding TrustedWebUtils, the TWA Helper.

Spreading the Manifest

If you are using the Java Support library, a splash screen might be created for you automatically but other properties from the manifest won’t be used. In fact, in my testing, I couldn’t see the theme-color being applied yet when my PWA is on the screen.

URL Validation

With Digital Asset Links you must serve under your PWA’s domain a file in the URL <your-domain>/.well-known/assetlinks.json. That JSON file will contain information about your Android package (such as the package ID) and a hash of your app’s certificate that you can get running a command in the terminal. Your Android package will have a counterpart setting the host URL. There is an online validator tool available to check if everything is fine.

If you don’t do the handshake, TWAs won’t be activated and your app will just use normal Chrome Custom Tabs with a Chrome user interface similar to when your PWA has display: minimal-ui. I’m not completely sure but I guess the Play Store might reject apps that are just pointing to normal Custom Tabs and not validated TWAs. I’m not completely sure yet when Chrome is doing the Digital Asset Link check; if it’s being done on every access to the app before opening it as a TWA it might be a performance problem. I guess a cache will be possible, and also the Play Store might check this before accepting the app. We’ll see if future documentation gives us clarity on this matter.

There is a (not so simple) mechanism to bypass the Digital Asset Link certification process for development purposes, explained below in this article.

Publishing your App

To publish in the Google Play Store you must accept developer agreement and pay a one time USD $25 registration fee

Deployment

The Google Play Console

Filling a lot of metadata and graphic assets will be mandatory for publishing your PWA in the Google Play Store

Updating your App

Limitations

PWAs in Subfolders

  • Digital Asset Link connects the whole domain, not just a folder
  • The current Support Library seems to handle as an Intent (Link Capturing) the whole host, even if your PWA is in a subfolder

No internal apps

That won’t be possible as Digital Asset Link works only with public URLs because Chrome needs to verify we own the domain, and that’s is not possible with internal URLs yet.

First Load experience

Calling native code

There is a potential here to bridge native code and JavaScript code without too much effort and let our PWAs access native code, similar to what happens when we publish an APPX with a PWA for Microsoft Store.

I’m seeing a future version with a way to register Java/Kotlin classes to the TWA Client so we can actually call them with a JavaScript API when our PWA is rendered in TWA mode.

Today, the only way to execute native code is to use Intents to open other native Activities and back opening TWA sending and receiving arguments through URIs parameters.

Also, you can create some kind of web server, or WebSocket server in native code running on a Service and let the PWA talk to it, but it’s kind of weird, complicated and maybe battery consuming. But there is a whole new world that might open now. Let’s see what the community creates!

Monetization with the Play Store

Debugging

Other engines

*UPDATE 2/4: The TWA works over the Android Custom Tab protocol that other browsers are currently implementing, so if the user doesn’t have Chrome or has changed the default browser, another browser might take precedence and open the TWA with the PWA content. More testing is needed to understand how it works.

What happens if the user has an older version of Chrome and installs the app from the Play Store? In this case, your PWA will appear as a Chrome Custom Tab, not in a completely standalone mode.

Google Maps Go in the Play Store was already using something similar to TWA specifying Chrome as a requirement

What happens if the user doesn’t have Chrome at all? As of today using the Support Library, your app won’t work at all (unless there is another browser listening to the Custom Tabs protocol). If you are using the TWA API on your own Java/Kotlin code you might be able to detect browser availability and load an alternate solution, such as a WebView or opening the browser.

While it’s not so common to see Android devices without Chrome, there are some devices without it by default, including new devices in Europe shipping without Chrome by default.

Other platforms

Conflicting with WebAPK

Two Starbucks Apps running at the same time: WebAPK and our own APK

You can stop Chrome to offer WebAPK and offer your store listing app instead by using the related_applications attribute and prefer_related_applications Web App Manifest’s attributes. Get Installed Related Apps API might help in the future with this conflict.

Detecting a Trusted Web Activity (*UPDATE 2/7)

  • Add an argument to the start URL the TWA will load
  • Use the Referrer: On the first navigation page load in a TWA, document.referrer will be set as android-app://<package-name>; the same value will also be set as well in the HTTP Header Referer (misspelled in the HTTP spec)

Creating your first PWApk

This article is an introduction and I’m working in a tutorial series, so if you are interested in that, follow me on Twitter or subscribe to my newsletter.

A few years ago I did a video course on Native Web Apps for Android, that while not exactly what you need to do for PWAs, it will help web developers understand the Android ecosystem.

The simplest way to make a TWA-based APK is to clone the SVGOMG repository sample from ChromeLabs GitHub repository

You can clone the git repository or start a new project.

In our case, we will start a new project just to understand and explain what’s going on with the solution.

Create a new Project in Android Studio and select “No Activity” as we will use just a Trusted Web Activity provided by the Support Library.

We start with an empty project

Fill the details, picking a name (we will override this later), and a Package name. The package name is important as it will be the ID of our app in the Android OS and also within the store. I recommend using your PWA’s host in reserve order and an optional name after, such as: com.mypwa.calculator if your PWA is https://mypwa.com/calculator

API 19 (Android 4.4) as a base looks good, as it seems that is going to be the minimum version required for Chrome soon. Some things on TWA will work only from API 23 (Android 6.0) but the Support Library will take care of that.

*UPDATE 2/5: Chrome formally announced that TWAs work only from Android 4.4 KitKat. There is around 5% of active Android users that won’t have the feature and they will fall back to a Custom Tab experience with a URL bar.

Picking the minimum API level will limit the devices that will see our PWA in the Google Play Store

Adding Dependency

There are two gradle configuration files, one for the project and one for the Android app

Starting with the Project build.gradle, we will add under allprojects > repositories, the following line:

maven { url "https://jitpack.io" }

Next step, we open the Module build.gradle and we add under dependencies:

implementation 'com.github.GoogleChrome:custom-tabs-client:e446d08014'

Configuring the TWA

manifestPlaceholders = [
hostName: "app.starbucks.com",
defaultUrl: "https://app.starbucks.com",
launcherName: "Starbucks",
assetStatements: '[{ "relation": ["delegate_permission/common.handle_all_urls"], ' +
'"target": {"namespace": "web", "site": "https://app.starbucks.com"}}]'
]

In this case, I’ll use the Starbucks PWA as an example. The assetStatements key is the one that will need information from the Digital Asset Link process. We’ll skip that part for development purposes. The property with the name launcherName should match short_name in the Web App Manifest.

Configuring the Manifest

The default Android Manifest file we have now

There, we can change the value of android:label with ${launcherName} to use the launcherName we set before in the metadata, so we will have one single source of truth for the app’s name.

The next step is to setup this file, starting with opening the <application> tag so we can add some children inside that will look like the following code:

<meta-data
android:name="asset_statements"
android:value="${assetStatements}" />

<activity android:name="android.support.customtabs.trusted.LauncherActivity"
android:label="${launcherName}">
<meta-data android:name="android.support.customtabs.trusted.DEFAULT_URL"
android:value="${defaultUrl}" />

<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="https"
android:host="${hostName}"/>
</intent-filter>
</activity>

The code below will set up the TWA using the Support Library, the Intent Filter so your app will capture links to your PWA and the Digital Asset Link. I will skip the details on what’s going on there from an Android app’s point of view.

It’s time to Sync

At this point, you will have to make Android Studio take all your changes by clicking on “Sync Now.” If everything is correct, you won’t get any errors at this point.

Icon replacement

We need to manually take icons from our Manifest and copy them in the mipmap subfolders with the right name

Theme adjustment

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:backgroundDimEnabled">false</item>
</style>

You can change the colors of the app from app/res/values/colors.xml but I didn’t see them yet in the TWA.

If you are currently restricting orientation in your manifest, you might also want to add that restriction in the <activity> element in the AndroidManifest.xml.

Ready to test?

Setting up Chrome

Next, we need to set up Chrome to bypass Digital Asset Link for the host we want to test, in our example: app.starbucks.com. (I’m sorry Starbucks, but we love you, you know that LOL)

To change command line arguments for Chrome on Android we need to write a text file in the Android’s file system. The simplest way to do it is through adb (android debug bridge) that has to be in the path (google that if it’s not there) and execute:

adb shell cat /data/local/tmp/chrome-command-line _ - disable-digital-asset-link-verification-for-url="https://app.starbucks.com"

There is a simple bash script available in the Chrome’s sample to use if you want to.

We need to stop Chrome to take our new dev setting

And now, we need to restart Chrome. But not just killing the app from the multitask window. Go the Settings / Apps / Chrome and Terminate the whole process (Force Stop). I had to do this a couple of times before having it ready.

The warning stating that the flag is enabled

If it’s done, then every time you open chrome you will get a warning now about that flag we enabled and if you run your app from Android Studio you will finally get your PWA up and running in standalone more under your APK’s icon and name.

Conclusion

I was questioning if Google was approving or not TWAs, so they are removing the suspicious at least of the TWA part of the article.

Let’s take Chrome 72 TWA as the first step of a long journey!

I want to thank Paul Kinlan for his support regarding TWAs, my questions and because I’ve been pinging him almost every month about this :P

Maximiliano Firtman is an independent mobile + web developer, trainer, speaker, and author. He has authored many books, including High-Performance Mobile Web published by O’Reilly Media. He is a frequent speaker at conferences worldwide and he has been widely recognized for his work in the mobile-web community. He teaches mobile, JavaScript, PWA and web performance trainings for top companies around the world. He is an independent consultant and he has delivered several PWAs workshops and courses at many companies and at online publishers, such as Linked Learning/Lynda and Safari. Twitter: @firt

Maximiliano Firtman

Written by

mobile+web developer, author, trainer, speaker | firt.mobi