Create passes on Android using the Google Wallet API

1. Introduction

Overview

The Google Wallet API allows you to engage with users through various types of passes: loyalty cards, offers, gift cards, event tickets, transit tickets, boarding passes, and more. Each pass type, or pass class, comes with use-case specific fields and features to enhance the user experience.

However, these might not fit every use case. To create a more customized experience, you can use the generic pass type. Here are some example use cases for the generic pass type:

  • Parking passes
  • Library membership cards
  • Stored value vouchers
  • Gym membership cards
  • Reservations

You can use generic passes for any use case that can be presented with:

  • Up to three rows of information
  • (Optional) Barcode graphic
  • (Optional) Details section

An Android-powered device demonstrating the Add to Google Wallet provisioning flow

For more information on the Google Wallet API, or adding an Add to Google Wallet button to an Android application, please see the Google Wallet developer documentation.

Pass classes and objects

The Google Wallet API exposes methods to create the following:

Type

Description

Pass class

A template for an individual pass object. It contains information common to all pass objects that belong to this class.

Pass object

An instance of a pass class that is unique to a user ID.

About this codelab

In this codelab, you will complete the following tasks.

  1. Create a new issuer account in demo mode
  2. Create a service account for issuing passes
  3. Create a new Generic pass class
  4. Create a new pass object
  5. Create an Add to Google Wallet button to save a pass
  6. Display the button in your Android app
  7. Handle the pass save result

Prerequisites

Objectives

After completing this codelab, you will be able to do the following:

  • Add the Google Wallet SDK to your Android app
  • Check if the Google Wallet API is available on an Android-powered device
  • Create an Add to Google Wallet button

Support

If you are stuck at any point in the codelab, the google-pay/wallet-android-codelab GitHub repository contains a complete solution for reference.

2. Setup

In this step, you will create an Issuer account in demo mode. This will allow you to create pass classes and objects that can be added to user wallets. Next, you will create a Google Cloud project and service account. These will be used to programmatically create pass classes and objects in the same manner as a backend server. Last, you will authorize the Google Cloud service account to manage passes in your Google Wallet issuer account.

Sign up for a Google Wallet API issuer account

An Issuer account is necessary to create and distribute passes for Google Wallet. You can sign up using the Google Pay & Wallet Console. Initially, you will have access to create passes in demo mode. This means that only specific test users will be able to add passes you create. Test users can be managed in the Google Pay & Wallet Console.

For more information on demo mode, see the Generic pass prerequisites.

  1. Open the Google Pay & Wallet Console
  2. Follow the on-screen instructions to create an Issuer account
  3. Select Google Wallet API
  4. Confirm you understand the terms of service and privacy policy
  5. Copy the Issuer ID value to a text editor or other location
  6. Under the Manage tab, select Set up test accounts
  7. Add any email addresses you will use in this codelab

Enable the Google Wallet API

  1. Sign into the Google Cloud console
  2. If you don't already have a Google Cloud project, create one now (see Creating and managing projects for more information)
  3. Enable the Google Wallet API (also referred to as Google Pay for Passes API) for your project

Create a service account and key

A service account and a service account key are necessary to call the Google Wallet API. The service account is the identity that calls the Google Wallet API. The service account key contains a private key that identifies your application as the service account. This key is sensitive, so keep it confidential.

Create a service account

  1. In the Google Cloud console, open Service Accounts
  2. Enter a name, ID, and description for your service account
  3. Select CREATE AND CONTINUE
  4. Select DONE

Create a service account key

  1. Select your service account
  2. Select the KEYS menu
  3. Select ADD KEY, then Create new key
  4. Select the JSON key type
  5. Select CREATE

You will be prompted to save the key file to your local workstation. Make sure to remember its location.

Set the GOOGLE_APPLICATION_CREDENTIALS environment variable

The GOOGLE_APPLICATION_CREDENTIALS environment variable is used by Google SDKs to authenticate as a service account and access different APIs for a Google Cloud project.

  1. Follow the instructions in the Google Cloud Service account keys documentation to set the GOOGLE_APPLICATION_CREDENTIALS environment variable
  2. Verify the environment variable is set in a new terminal (MacOS/Linux) or command-line (Windows) session (you may need to start a new session if you have one open already)
    echo $GOOGLE_APPLICATION_CREDENTIALS
    

Authorize the service account

Lastly, you will need to authorize the service account to manage Google Wallet passes.

  1. Open the Google Pay & Wallet Console
  2. Select Users
  3. Select Invite a user
  4. Enter the email address of the service account (e.g. test-svc@myproject.iam.gserviceaccount.com)
  5. Select either Developer or Admin from the Access level drop-down menu
  6. Select Invite

3. Create a Generic pass class

In this step, you will create the base class for your pass. Any time a new pass is created for a user, it will inherit the properties defined in the pass class.

The pass class you will create during this codelab uses the flexibility of Generic passes to create an object that works as both an identity badge and challenge points tracker. When a pass object is created from this class, it will look like the following graphic.

Pass classes can be created directly in the Google Pay & Wallet Console or by using the Google Wallet API. In this codelab, you will create the Generic pass class using the API. This follows the process a private, backend server would use to create pass classes.

  1. Clone the google-pay/wallet-android-codelab GitHub repository to your local workstation
    git clone https://github.com/google-pay/wallet-android-codelab.git
    
  2. Open the cloned repository in your terminal or command-line prompt
  3. Navigate to the backend directory (these scripts imitate backend server actions)
    cd backend
    
  4. Install the Node.js dependencies
    npm install .
    
  5. In the backend directory, open generic_class.js
  6. Replace the value of issuerId with your Issuer ID from the Google Pay & Wallet Console
    // TODO: Define Issuer ID
    let issuerId = 'ISSUER_ID';
    
  7. In your terminal or command-line prompt, run the generic_class.js script
    node generic_class.js
    

When your code runs, it will create a new pass class and output the class ID. The class ID is made up of the issuer ID followed by a developer-defined suffix. In this case, the suffix is set to codelab_class (the class ID would look similar to 1234123412341234123.codelab_class). The output logs will also include the response from the Google Wallet API.

4. Open the project in Android Studio

The GitHub repository you cloned contains an Android project with an empty activity. In this step, you will edit in this activity to include an Add to Google Wallet button on a product page.

  1. Open Android Studio
  2. Select File, then Open
  3. Select the android directory in the repository
  4. Select Open

Add the Google Wallet SDK to your app

  1. Open the module-level Gradle build file (android/app/build.gradle)
  2. Add the Google Wallet SDK to the dependencies section
    // TODO: Add the "com.google.android.gms:play-services-pay" dependency to
    //       use the Google Wallet API
    implementation "com.google.android.gms:play-services-pay:16.0.3"
    
  3. Save the file
  4. Select File, then Sync Project with Gradle Files

5. Create the Add to Google Wallet button

In this step, you will create an Add to Google Wallet button and add it to an existing activity. The assets for the button have already been included in the project. To include the button, you will create a separate layout file. Once added, the button will look like the following.

The Add to Google Wallet button

  1. Create a new layout file: app/src/main/res/layout/add_to_google_wallet_button.xml
  2. Add the following content to the new layout file
    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="48sp"
        android:background="@drawable/add_to_google_wallet_button_background_shape"
        android:clickable="true"
        android:contentDescription="@string/add_to_google_wallet_button_content_description"
        android:focusable="true">
      <ImageView
          android:layout_width="227dp"
          android:layout_height="26dp"
          android:layout_gravity="center"
          android:duplicateParentState="true"
          android:src="@drawable/add_to_google_wallet_button_foreground" />
    </FrameLayout>
    
  3. Include the add_to_google_wallet_button.xml layout in the checkout activity layout file (app/src/main/res/layout/activity_checkout.xml)
    <!--
        TODO: Create the button under `add_to_google_wallet_button.xml`
              and include it in your UI
    -->
    <include
        android:id="@+id/addToGoogleWalletButton"
        layout="@layout/add_to_google_wallet_button"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:layout_marginTop="10dp" />
    

6. Check if the Google Wallet API is available

If a user opens your app on a device that does not support the Google Wallet API, it may create a negative experience when they try to add the pass. If the user's device does not support the Google Wallet API, hiding the Add to Google Wallet button avoids potential confusion. There are various reasons why the API may be unavailable, such as the Android or Google Play Services versions being out of date or Google Wallet being unavailable in the user's country.

In this step, you will add logic to your app that checks if the Google Wallet API is available on the device. If so, the button will be rendered in the activity. Otherwise, the button will be hidden.

  1. Open the CheckoutActivity.kt file in app/src/main/java/com/google/android/gms/samples/wallet/activity/
  2. Create a class property for the PayClient instance
    // TODO: Create a client to interact with the Google Wallet API
    private lateinit var walletClient: PayClient
    
  3. Instantiate the PayClient property in the onCreate method
    // TODO: Instantiate the client
    walletClient = Pay.getClient(this)
    
  4. Create a method that checks if the Google Wallet SDK and API are available on the device and handle the result
    // TODO: Create a method to check for the Google Wallet SDK and API
    private fun fetchCanUseGoogleWalletApi() {
      walletClient
        .getPayApiAvailabilityStatus(PayClient.RequestType.SAVE_PASSES)
        .addOnSuccessListener { status ->
          if (status == PayApiAvailabilityStatus.AVAILABLE)
            layout.passContainer.visibility = View.VISIBLE
        }
        .addOnFailureListener {
          // Hide the button and optionally show an error message
        }
    }
    
  5. Call the fetchCanUseGoogleWalletApi method in the onCreate method to check whether the Google Wallet API is available
    // TODO: Check if the Google Wallet API is available
    fetchCanUseGoogleWalletApi()
    

When you run the app, you should now see the Add to Google Wallet button in the UI.

The Add to Google Wallet button now appears in the app activity

7. Create a Generic pass object

Now that you have verified that the Google Wallet API is available, you can create a pass and prompt your user to add it to their wallet. There are two flows for creating pass objects for users.

Create the pass object on the backend server

In this approach, the pass object is created on a backend server and returned to the client app as a signed JWT. This is best suited for cases where user adoption is high, as it ensures the object exists before the user tries to add it to their wallet.

Create the pass object when the user adds it to their wallet

In this approach, the pass object is defined and encoded into a signed JWT on the backend server. An Add to Google Wallet button is then rendered in the client app that references the JWT. When the user selects the button, the JWT is used to create the pass object. This is best suited for cases where user adoption is variable or unknown, as it prevents pass objects from being created and not used. This approach will be used in the codelab.

  1. Open the backend/generic_pass.js file
  2. Replace the value of issuerId with your Issuer ID from the Google Pay & Wallet Console
    // TODO: Define Issuer ID
    let issuerId = 'ISSUER_ID';
    
  3. In your terminal or command-line prompt, run the generic_pass.js file
    node generic_pass.js
    
  4. Copy the output token to your clipboard or a text editor

When your code runs, it will define a new pass object and embed it in a JWT. The JWT is then signed by the service account key you created previously. This authenticates the request to the Google Wallet API so that credentials do not need to be stored in the client app.

aside In a production environment, your backend system would be responsible for creating JWTs and returning them to clients. In this codelab, the generic_pass.js script emulates this behavior and "returns" a token for you to use in the client app.

8. Add the pass to Google Wallet

Now that you have verified that the Google Wallet API is available and have created a signed JWT, you can prompt the user to add the pass to their wallet. In this step, you will add a listener to the Add to Google Wallet button that uses the Google Wallet API to save the pass in the user's wallet.

  1. Open the app/src/main/CheckoutActivity.kt file
  2. Replace the value of token with the JWT you created previously
    // TODO: Save the JWT from the backend "response"
    private val token = "TOKEN"
    
  3. Create a class property to store the request code
    // TODO: Add a request code for the save operation
    private val addToGoogleWalletRequestCode = 1000
    
  4. Set a listener for the Add to Google Wallet button
    // TODO: Set an on-click listener on the "Add to Google Wallet" button
    addToGoogleWalletButton = layout.addToGoogleWalletButton.
    
    addToGoogleWalletButton.setOnClickListener {
      walletClient.savePassesJwt(token, this, addToGoogleWalletRequestCode)
    }
    

When a user selects the Add to Google Wallet button, the walletClient.savePassesJwt method is called. This method prompts the user to add the new pass object to their Google Wallet.

9. Handle the savePassesJwt result

In the final step of this codelab, you will configure your app to handle the result of the walletClient.savePassesJwt operation.

  1. Open the app/src/main/CheckoutActivity.kt file
  2. Override the onActivityResult method to contain the following code
    // TODO: Handle the result
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
      super.onActivityResult(requestCode, resultCode, data)
    
      if (requestCode == addToGoogleWalletRequestCode) {
        when (resultCode) {
          RESULT_OK -> {
            // Pass saved successfully. Consider informing the user.
          }
    
          RESULT_CANCELED -> {
            // Save canceled
          }
    
          PayClient.SavePassesResult.SAVE_ERROR ->
            data?.let { intentData ->
              val errorMessage = intentData.getStringExtra(PayClient.EXTRA_API_ERROR_MESSAGE)
              // Handle error. Consider informing the user.
              Log.e("SavePassesResult", errorMessage.toString())
            }
    
          else -> {
            // Handle unexpected (non-API) exception
          }
        }
      }
    }
    

Now your app is able to handle the following scenarios:

  • Successful pass addition
  • User cancellation
  • Unexpected errors

Run your app to confirm that you can add the pass and handle the result as expected.

10. Congratulations

An example Generic pass object.

Congratulations, you have successfully integrated the Google Wallet API on Android!

Learn more

Take a look at the complete integration in the google-pay/wallet-android-codelab GitHub repository.

Create passes and request production access

When you are ready to issue your own passes in production, go to the Google Pay & Wallet Console to request production access and authorize your Android app.

See the Android SDK Prerequisites to learn more.