Skip to content

This sample demonstrates how you can publish your Progressive Web App (PWA) on Google Play Store with Trusted Web Activities (TWA), and use Digital Goods API and Payment Request API to receive payments with Google Play Billing.

License

Apache-2.0 and 2 other licenses found

Licenses found

Apache-2.0
LICENSE
Unknown
license-config.json
Unknown
license-header
Notifications You must be signed in to change notification settings

chromeos/pwa-play-billing

PWA Play Billing Sample Setup

Introduction

This sample app demonstrates how you can publish your Progressive Web App (PWA) using Trusted Web Activities (TWA) on Google Play Store and receive payments with Google Play Billing using Digital Goods API and PaymentRequest API.

The sample uses Firebase for static hosting and backend server operations for simplicity. However, you can use any other service to publish on Play Store and use Play Billing as well.

Checkout and setup

$ git clone https://github.com/chromeos/pwa-play-billing
$ cd pwa-play-billing
$ npm install
$ cd functions
$ npm install
$ cd ..
$ npm start

Firebase setup

Set up Firebase Account

  1. In order to start with Firebase, please visit the Firebase Console and create a Firebase account.
  2. Once your Firebase account is created, revisit the console and create a new project by clicking the “Add project” button

Add Firebase project.

  1. Create a unique name for your project. Below the name input box will be the project ID, write it down.

Create Firebase project name. Below, the full project ID is outlined.

  1. The next page is regarding activating Google Analytics for your Firebase project. Turn this option off as this is just a test application and we don’t need analytics activated.
  2. Firebase will then set up all the required resources for your project. When it’s done, you will see a “Your new project is ready” message with a continue option. Go ahead and click “Continue”.

Firebase Authentication

The sample requires users to be signed-in with an account before they can purchase and consume in-app purchases. User accounts also allow a user to access their purchases across multiple devices (purchases made via the Play Store on Chrome OS, can still be accessed on an Android device).

  1. To set up authentication, go to your project page in the Firebase Console
  2. In the left-hand menu, click to expand the “Build” section and choose “Authentication”.
  3. From there, click on the Sign-in method tab (If you see a “Get Started” button, clicking on it will take you to the same page as well).

Add a sign-in method for Firebase authentication.

  1. Click on the Google provider in the Sign-in providers list.
  2. Turn the switch on to enable the Google Provider.
  3. Give the project a unique name as this will be what is presented to your users to identify your app.
  4. Choose an email address for the project support email.
  5. Click Save to confirm changes.

Choose a project support email.

The sample code loads the authentication method without needing to pass in the Web SDK configuration information because Firebase Hosted Configuration handles this automatically. To learn more about authentication, please visit the Firebase documentation here.

Firebase Hosting

  1. In the left hand navigation menu for your project in the Firebase console, click on the “Hosting” option. At the top of the page should be a Get Started link, click on it.

Firebase Hosting is outlined in Firebase console menu.

  1. The Get Started button will provide the command to install the Firebase CLI. That command is:

    $ npm install -g firebase-tools
    
  2. After installing the Firebase CLI, you will need to login to Firebase. You can use the following command:

    $ firebase login
    
  3. Finally, in the downloaded project, in the .firebaserc file and the firebase.json file, replace <FIREBASE_PROJECT_ID> with your project ID you noted down earlier when you first created the Firebase project.

    // firebase.json
    {
    "hosting": {
        "site": "<FIREBASE_PROJECT_ID>",
        "public": "src",
    ...
    
    // .firebaserc
    {
    "projects": {
        "default": "<FIREBASE_PROJECT_ID>"
    }
    

The frontend code can be found here.

Firebase Functions

A large portion of granting purchase entitlements is controlled from the backend. The sample uses Firebase Functions to implement the backend functionality, as well as the real time developer notifications (RTDN).

Note: To use Firebase Functions, we need to enable a Blaze billing plan. The Blaze billing plan offers a free starting quota to test this project without the need to incur costs. As you experiment and grow, your costs may grow as well, so it would be beneficial to test the project as necessary and address any cleanup operations that may be necessary to reduce costs.

  1. To upgrade your project’s billing plan, click on the Functions option in the left hand navigation menu for your project in the Firebase Console.

  2. Click on “Upgrade project”

  3. Confirm that the selected plan is Blaze.

    Note: If you don’t have a billing account yet, Firebase will take you to the flow to create a billing account. Complete the steps to create a billing account, and go back to Step 1.

Setup billing account with Blaze plan.

  1. Click Purchase to switch to the Blaze billing plan.

Click "Purchase".

  1. You can also set a budget alert to avoid unexpected bills in the confirmation page.

Set a budget alert.

Firebase Cloud Firestore

This sample uses Firebase Cloud Firestore to store user information.

  1. To set up Firestore, visit the Firestore tab in the Firebase Console and click Create Database.

Cloud Firestore in Firebase console.

  1. In the first step, choose “production mode” to keep the data private and click Next. The Admin SDK in the sample functions code handles the communications with the database.
  2. In the second step, choose a Cloud Firestore location. Pick something close to your location where your functions are deployed. Then click Enable.

There are three key collections of data as shown below (Note that the document id was omitted from the tables as it is auto-generated). The sample’s backend code automatically populates these tables with Firebase Functions. If you’d like to generate your own SKUs via the Google Play Console, make sure to add them to the SKUs collection in Firestore.


SKUS
Field Type Values
sku string Value of a SKU defined in the Google Play Console
type string One of {repeatable, onetime, subscription}. These values represent the purchase behavior.

tokens
Field Type Values
isValid boolean Verifies that this token provided was a valid token and can be used to identify purchases (prevents fraud)
purchaseToken string A unique token identifier supplied by Google Play
userDatabaseId string This references the users collection unique identifier for the user

users
Field Type Values
accountName string Name on the account
email string Email address
hasBasicSub boolean True if the user has the basic subscription
lastQueryTime number The last time that the user was queried from the database
numCoins number The number of coins that the user has. Coins are repeatable purchase items that accumulate.
photoEntitlements Array<string> One-time purchase items that the user has.
theme string The purchase made by using the repeatable purchase item. (i.e., the user purchased a red theme using coins that they purchased).

Request an origin trial token

On line 23 of index.html, you will see an option to insert an origin trial token. Visit this link to request an origin trial token for the Digital Goods API. Once you have your origin trial token, you can go and insert it on line 23 in the content attribute which currently holds the value $ORIGIN_TRIAL_TOKEN.

 <!-- Origin Trial -->
 <meta http-equiv="origin-trial" content="$ORIGIN_TRIAL_TOKEN" />

To learn more about setting up origin trials, please see this guide.

First deploy

After setting up Firebase, you can deploy just the hosting content first:

$ npm ci // Install the project
$ npm run deploy:hosting // Deploys only to hosting

You can now visit your PWA at https://<project_id>.web.app

Note that some functionality is still missing. We’ll set them up in the following sections and redeploy the app.

Google Play Console setup

General setup

To list your TWA in the Google Play Store, you’ll need to create a developer account. There is a one-time $25 registration fee.

After your developer account is set up, go to “All apps” in the left navigation menu and select “Create app”. Once you fill out the required fields to create your app, you’ll be brought to the “Dashboard” where you’ll find step-by-step task guides to test, setup, and release your app. For more information on creating a new app, visit Play Console help page.

Package your PWA with Bubblewrap

Bubblewrap is a command-line tool that will wrap your PWA in a Trusted Web Activity and output AAB and APK files that can be uploaded to the Play Console. To use Bubblewrap you need Node.js 10.0 or above.

During your first time running Bubblewrap, it will give you the option to download and install the dependencies, or you may set them up manually yourself. We recommend checking out the quickstart guide for more details.

Install Bubblewrap

$ npm i -g @bubblewrap/cli

Initialize project

$ mkdir <new-project-dir>
$ cd <new-project-dir>
$ bubblewrap init --manifest https://<project.id>.web.app/manifest.json

This init command will parse the manifest and prompt you to enter or confirm values for your Android project. Fill out the “Application name” and “Short name” as you would like your app name to appear (note that you are restricted to 12 characters for “short name”).

Bubblewrap init prompt for app info.

If you have an existing listing in the Play Store:

  1. For “Application ID”, use your existing package name when asked.
  2. Make sure to enter a version code higher than its existing versions.
  3. When prompted for “Key store location” and “Key name”, pass in the same key store location and key name that you used before. Otherwise the Play Console will reject your new upload because you’ve signed it with different keys.

If you’re planning to create a new listing:

  1. For “Application ID”, choose a new unique package name.
  2. Leave the version code as is (default value of 1).
  3. For “Key store location” and “Key name”, you may use the default or enter your preferred path and name. Bubblewrap will then let you know that it couldn’t find a key store at the provided path. Enter “Yes” to let it create a new signing key. Remember the passwords you entered for your new key store and key as you’ll be prompted for them later on when you build.

When the prompt asks you whether to enable Play Billing, respond “Yes”.

Bubblewrap init prompt for enabling Play Billing feature.

Build

$ bubblewrap build

After successfully building your project, in your project directory, you’ll see the APK (app-release-signed.apk) and AAB (app-release-bundle.aab) you can upload to your Play Console (next section).

Note that if you skipped the step for updating your Digital Asset Links above, you may receive a warning message which is safe to ignore for now.

Read more about setting up Digital Asset Links at: https://developers.google.com/web/android/trusted-web-activity/quick-start#creating-your-asset-link-file

Failed to run the PWA Quality Criteria checks. Skipping.

Upload your app to Google Play

Only if you have a new listing

Follow the tasks in the “Set up your app” section in the dashboard before moving on.

In Play Console app Dashboard, the "Set up your app" checklist.

Upload your package

  1. We recommend you to publish to Internal Testing Track to speed up the time to start testing in the Play Store. You can access the Internal Testing Track by choosing on Internal testing on the left hand side menu.

In Play Console, Internal testing page.

  1. Click on the “Create new release” button.
  2. If you haven’t uploaded a package before, Play Console will offer you to opt in for Play App Signing. This is highly recommended. Click Continue to opt in.
  3. Click on the Upload button and choose the app-release-bundle.aab package generated by Bubblewrap.
  4. Fill in “Release name” and “Release notes” fields and click Save.
  5. Click on “Review release”.
  6. Review the release and click on “Start rollout to Internal testing”. If you see a warning with the following message, you can ignore it for now. We’ll configure testers in the next step.

Note: This release will not be available to any users because you haven't specified any testers for it yet. Tip: configure your testing track to ensure that the release is available to your testers.

Choose Testers

  1. Click on Testers tab under Internal testing page

Add testers on the Internal testing page.

  1. Either click on “Create email list” to create a new testers list. Add email addresses of your testers into this list and save. You can also edit an existing list by clicking on the right arrow button.
  2. Enable your testers list by clicking on the checkbox next to it.
  3. Save changes.

Enable testers list by clicking checkbox for each list name.

  1. Click on the Copy link button under the “How testers join your test” to retrieve the URL to your testing track. Share this link with your testers. Testers need to follow this link and opt-in for receiving the testing version first to install your app.

Copy link for URL to your testing track.

Run the app

Now that the app is uploaded to Play Store, you should be able to opt-in for the testing track by following the test URL (copied above), and install the app through Play Store and run it on your device. Note that some functionality is still missing, and we’ll configure them in the following steps.

Set up SKUs for in-app products and subscriptions

This section will cover the steps to set up your in-app products and subscriptions which will be purchasable via the Digital Goods API.

In the left-hand navigation menu, scroll down until you see the “Monetize” section and expand the “Products” menu. If you don’t see the “Monetize” section, make sure you’re in the app menu and not the general user menu. To see the app menu, go to “All apps” and select the corresponding app.

If you see “Missing requirements for accessing this page”, follow the instructions to set up a merchant account and come back to this page later.

In-app products

  1. Click on “In-app products”.
  2. Click on the “Create product” button.
  3. Enter coins_100 as the Product ID. This cannot be changed later.
  4. Fill in the name and description fields. Set a price, for example $1. You can always edit these fields later.
  5. Click Save and then Activate.

Repeat this process for these Product IDs:

  • coins_200
  • coins_1000
  • onetime

Subscriptions

  1. Click on “Subscriptions”.
  2. Click on the “Create subscription” button.
  3. Enter basic_sub as the Product ID. This cannot be changed later.
  4. Fill in the name and description fields.
  5. Set a billing period (e.g weekly) and price, for example $10. Note that the billing period cannot be changed later.
  6. Click Save and then Activate.

Notes

If you’d like to add your own SKUs, be sure to note down the “Product ID”s as that’s how they’ll be identified by the Digital Goods API. In the case of our sample code, we obtain the product IDs from the SKUs collection we populated in Firestore (see above). So make sure the SKUs you’ve added in the Play Console matches the information in the SKUs collection in Firestore (and vice versa). If not, please adjust either accordingly so they are aligned.

Second Deploy

Now that you’ve successfully created your TWA and uploaded it to the Play Console, it’s time to update the missing information and redeploy your PWA again.

Update “View In Play Store” link

After your first deploy, you might have noticed that when checking your PWA at https://<project.id>.web.app, clicking on the user profile icon will show a menu. One of the menu items is “View In Play Store” and clicking on it will take you to a broken link. Now that you’ve uploaded your app to the Play Store and released it to the internal testing track, you can update this link! In ./src/js/components/profile-menu.html replace <PLAY_PACKAGE_NAME> with your app’s package name for easy access to install the TWA.

// profile-menu.html
...
 _showPlayStore() {
window.open('https://play.google.com/store/apps/details?id=<PLAY_PACKAGE_NAME>','_blank');
...

Update the Web App manifest.json

To link your web application to the Android app, you will also need to reference in your web app’s manifest.json (./src/manifest.json file) the Android package name. Replace the two instances of <PLAY_PACKAGE_NAME> with your app’s package name.

// manifest.json
{
 ...
 "android_package_name": "<PLAY_PACKAGE_NAME>",
 "prefer_related_applications": true,
 "related_applications": [
  {
   "id": "<PLAY_PACKAGE_NAME>",
   "platform": "chromeos_play",
  }
 ],
 ...

Update Digital Asset Links

In order to publish your app to the Google Play Store and have your app be connected to the Play Store for purchasing, users need to use Digital Asset Links to validate that relationship. In our sample, this is done by publishing a Digital Asset Links JSON file at https://<project.id>.web.app/.well-known/assetlinks.json.

Update the ./src/.well-known/assetlinks.json file by replacing <PLAY_PACKAGE_NAME> with your app’s package name and <SIGNING_KEY_CERT> with your signing key’s SHA-256 fingerprint. You can find the SHA-256 certificate fingerprint in “App Integrity” under the “Setup” section in the left hand menu of the Play Console or use this link and choose your developer account and then your app to be redirected.

// assetlinks.json
[
 {
   "relation": ["delegate_permission/common.handle_all_urls"],
   "target": {
    "namespace": "android_app",
    "package_name": "<PLAY_PACKAGE_NAME>",
    "sha256_cert_fingerprints": ["<SIGNING_KEY_CERT>"]
   }
 }
]

For information on Digital Asset Links, please check out the following YouTube video:
Validating your Trusted Web Activity’s Digital Asset Links.

Re-deploy

After updating the manifest.json and assetlinks.json files, remember to re-deploy your project to update your PWA.

$ npm run deploy

Double-check the manifest and asset links at https://<project.id>.web.app/manifest.json and https://<project.id>.web.app/.well-known/assetlinks.json to make sure they’ve updated.

Google Play Developer API

Like in our sample, it is highly recommended that you verify purchases and tokens in your backend server with the Google Play Developer API, alongside using the Digital Goods API in your PWA. There are two main configuration steps before you can use the API in your backend code.

Link API Project to your Play Console

To link your Google Cloud project in the Play Console, go to the “API access” section in the left-hand navigation general user menu (not the app menu). This is under “Settings” > “Developer account” > “API access”.

In Play Console, API access page.

You can either “Link an existing project” or “Create a new project”. If you don’t see your existing project in the drop-down menu, first verify that the email you’ve used for your developer Play Console account is listed as an “Owner” in the API Console and that it has the Google Play Android Developer API enabled in the API Library (it may take up to a couple hours after you’ve done these for your project to be listed in the Play Console).

If you create a new project, the API will automatically be enabled and linked for you. You can always unlink and link a new Google Cloud project at any time.

Setup a service account

Backend services authenticate through a service account to access Google Play Developer API. To set up a service account as your API access client, scroll down to the “Service accounts” section on the same “API access” page.

If you had linked an existing API project with existing service accounts, you may see your available service accounts listed (you may need to click “Refresh service accounts”). If you don’t see your expected service accounts, check the service account permissions in the Google Cloud Platform (make sure you are in the right project). Your service account should have a suitable role; for our purposes “Service Account User” is sufficient. Then go back to the Play Console and refresh service accounts to see it listed.

If you don’t have a service account, follow these instructions to create a new service account.

  1. Click “Create new service account”

Create a new service account on the API access page.

  1. Follow the instructions and go to the Google Cloud Platform and click “+CREATE SERVICE ACCOUNT”.
  2. Fill in the details and click “Create”.
  3. Then complete step “2. Grant this service account access to project”. Though it is labeled optional, it isn’t in our case. We recommend adding the “Service Accounts” > “Service Account User” role.

On Google Cloud Platform, grant "Service Account User" role to service account.

  1. Step 3 is optional as labeled. Click Done to save your service account.
  2. Now go back to the Play Console, and click “Refresh service accounts” to see your new service account listed. Then click “Grant access” to give it permissions.

In Play Console, click to grant access to service account. In Play Console, the app permissions tab.

  1. Make sure “Manage orders and subscriptions permission” is checked.

Enable "Manage orders and subscriptions permission" for service account.

  1. Click “Invite user”.

Create service account key

Go back to the Google Cloud Platform. You may see that for the service account we just created/used, it says “No keys” under “Key ID”.

On Google Cloud Platform, table of service accounts.

To create a new key:

  1. Under the “Actions” three-dot menu, select “Manage keys”.

  2. In the window opened, click on “Add key” and choose “Create new key”.

  3. Choose your preferred format and click “Create”.

  4. It will then download a file that contains your private key. Store it somewhere safe and secure and don’t lose it! If you misplace it, you won’t be able to recover it but you can create another new key.

  5. Use your private key to fill out the missing service account credentials in the functions/src/config.ts file.

    1. Fill in the serviceAccountEmail const with the client_email from the private key file you downloaded.

    2. Copy the entire private key string (private_key) as is into the serviceAccountPrivateKey const.

      // config.ts
      ...
      // service account credentials
      export const serviceAccountEmail = '';
      export const serviceAccountPrivateKey = '';
      ...
      

Real-Time Developer Notifications (RTDN)

RTDN, which utilizes Google Pub/Sub, lets your backend server receive notifications from Google Play about any user’s entitlement changes. Specifically, RTDN is useful for subscriptions and essential if you have a cross-platform app.

Google Cloud Console setup

To set up RTDN, first sign in to the Google API Console, and make sure you are using the same project that you linked to the Play Console earlier when configuring Google Play Developer API.

Navigate to “APIs & Services” in the left hand menu. Then click “+ ENABLE APIS AND SERVICES”, search for “Cloud Pub/Sub API” and enable it.

In Google Cloud Console, enable APIs and services.

Then to create your Pub/Sub topic, go to the Pub/Sub topics page in the Cloud Console and click “+ CREATE TOPIC”.

Fill in the “Topic ID” and note down the full topic name for later.

Create a topic ID and below it the full topic name is outlined.

Then click on “ADD MEMBER” to add [email protected] with the “Pub/Sub Publisher” role which allows it to publish messages to the topic you’ve created.

Add the service account as a member to the topic.

Add the service account email with "Pub/Sub Publisher" role.

Play Console setup

Now that you’ve created a topic and added the Google Play developer notifications account, you’ll need to set up RTDN in your app in the Play Console. In the left-hand navigation menu, scroll down to the “Monetize” section and select “Monetization setup”. Add your topic name which we noted down earlier from the Pub/Sub console. Click “Save changes”.

In Play Console, add full topic name for RTDN.

Backend setup

In our sample, we use Firebase Cloud Functions as a serverless framework in place of a backend server to handle HTTP requests. Additionally, this is also how we receive the RTDN events and trigger corresponding events via Pub/Sub triggers. You’ll see in functions/src/index.ts a similar piece of code:

export const rtdnListener = functions.pubsub
 .topic(topicID).onPublish(async (data, context) => {
   // Read and handle the incoming Realtime Developer notification
 });

Earlier you added your service account credentials into the functions/src/config.ts file. Now, replace <PLAY_PACKAGE_NAME> with your Android app package name and <RTDN_TOPIC_ID> with your RTDN topic ID you created earlier

Note that you should just the topic ID (e.g. "play-rtdn") and not the full topic name.

// config.ts
...
// app package name
export const packageName = '<PLAY_PACKAGE_NAME>';

// RTDN pub/sub topic ID
export const topicID = '<RTDN_TOPIC_ID>';
...

If you have your own secure backend server, you should implement consuming the messages sent to your RTDN topic there, by using the Pub/Sub client libraries. For full Pub/Sub documentation, check out https://cloud.google.com/pubsub/docs/.

Final deploy

After updating the service account credentials and RTDN topic name, remember to re-deploy your project to update your PWA.

$ npm run deploy

Note: To resolve prettier errors, you can run the following command:

$ npm run prettier:fix

Testing

Set up your device

The Digital Goods API will be available on Chrome OS stable starting with version 89. In the meantime, it is possible to test the Digital Goods API by following these steps:

  1. Enable the Chrome OS dev channel
  2. Enable the following flags in Chrome by navigating to chrome://flags and searching for the flag by name.
    1. #enable-experimental-web-platform-features
    2. #enable-web-payments-experimental-features
    3. #enable-debug-for-store-billing
  3. Install your app from the Play Store on the device.

Set up License Testers

With application licensing, you can set up a list of Gmail accounts as License Testers to test your in-app billing & subscription integration. License testers have access to test payment methods that avoid charging the testers real money for purchases. You can also use test payment methods to simulate certain situations, such as when a payment is declined.

To add license testing accounts:

  1. Go to “All apps” in the left navigation menu and click on “License testing” under “Settings”.
  2. Fill in the “Add license testers” field.
  3. Click “Save changes”

In Play Console, add license testers.

See Test your Google Play Billing Library integration article for more information on License Testers and various test cases for different in-app products.

About

This sample demonstrates how you can publish your Progressive Web App (PWA) on Google Play Store with Trusted Web Activities (TWA), and use Digital Goods API and Payment Request API to receive payments with Google Play Billing.

Topics

Resources

License

Apache-2.0 and 2 other licenses found

Licenses found

Apache-2.0
LICENSE
Unknown
license-config.json
Unknown
license-header

Code of conduct

Stars

Watchers

Forks