Once you've created a pass and encoded it in a JWT, you are ready to issue it in your Android app. To do this, you will need to check that the Google Wallet API is available on the user's device, present them with an 'Add to Google Wallet' button, then save the pass to their Google Wallet once they tap the button.
Prerequisites
Before you try to issue a pass, be sure you have completed the following:
- Completed all of the steps in the Onboarding guide.
- Create at least one Passes Class.
- Create at least one Passes Object.
- Encoded your Passes Class and Passes Object in a JWT.
1. Install the Google Wallet Android SDK
To use the Google Wallet Android SDK, add com.google.android.gms:play-services-pay
to the dependencies
section of your app-level build.gradle
file:
implementation "com.google.android.gms:play-services-pay:16.5.0"
2. Check for Google Wallet API availability
Before saving the new object, ensure that the Google Wallet API is
available on the target device by calling thegetPayApiAvailabilityStatus
method in the PayClient
class.
Start by adding a member variable to the activity where you will show the button and instantiate it when the activity is created:
Kotlin
import com.google.android.gms.pay.PayClient
private lateinit var walletClient: PayClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
walletClient = Pay.getClient(this)
// Additional logic in your onCreate method
}
Java
import com.google.android.gms.pay.PayClient;
private final PayClient walletClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
walletClient = Pay.getClient(application);
// Additional logic in your onCreate method
}
If you are using other design patterns consider placing domain specific business logic appropriately. For example, if you are using the MVVM pattern, place UI related business logic in your Activity or Fragment (eg.: UI elements, activity result), and operational logic in your view model (eg.: client instantiation, network call triggers).
Next, use the PayClient
to check whether the API is available:
Kotlin
import com.google.android.gms.pay.PayApiAvailabilityStatus
private fun fetchCanUseGoogleWalletApi() {
walletClient
.getPayApiAvailabilityStatus(PayClient.RequestType.SAVE_PASSES)
.addOnSuccessListener { status ->
if (status == PayApiAvailabilityStatus.AVAILABLE) {
// The API is available, show the button in your UI
} else {
// The user or device is not eligible for using the Pay API
}
}
.addOnFailureListener {
// Hide the button and optionally show an error message
}
}
Java
import com.google.android.gms.pay.PayApiAvailabilityStatus;
private void fetchCanAddPassesToGoogleWallet() {
walletClient
.getPayApiAvailabilityStatus(PayClient.RequestType.SAVE_PASSES)
.addOnSuccessListener(status -> {
if (status == PayApiAvailabilityStatus.AVAILABLE) {
// The API is available, show the button in your UI
} else {
// The user or device is not eligible for using the Pay API
};
})
.addOnFailureListener(exception -> {
// Google Play Services is too old, or API availability not verified
// Hide the button and optionally show an error message
});
}
Finally, call the method you just defined in your application when you need to determine the availability of the API.
Handle when the API is unavailable
Some reasons why the API may be unavailable include the Android or Google Play services versions being out of date, or that Google Wallet is unavailable in the user's country.
If the API is not available consider hiding the button and falling back to a different integration (e.g. using a JWT link). Note that the user may become eligible to use the API in the future.
3. Add the 'Add to Google Wallet' button
Google Wallet provides a familiar button that you can use to trigger the Add to Google Wallet flow in your application. Vector assets for the button are available in the Button guidelines.
You can import vector assets in Android Studio under File > New > Vector Asset
. Select "Local file" in the wizard, add a name (eg.:
add_to_google_wallet_button.xml
) and locate the file in your local drive to import it.
Now, you can use the imported drawable to add the button to your user interface:
<ImageButton android:id="@+id/addToGoogleWalletButton" android:layout_width="match_parent" android:layout_height="48dp" android:minWidth="200dp" android:clickable="true" android:src="@drawable/add_to_google_wallet_button" />
The button has a layout_height
of 48 dp and must be at least 200 dp wide.
4. Add a pass to a user's Google Wallet
The LoyaltyObject
can be added by passing an unsigned JWT to the savePasses
method.
You can start the add operation as a result of clicking the Google Wallet
button.
Kotlin
import android.os.Bundle
import android.view.View
import com.google.android.gms.samples.wallet.databinding.ActivityCheckoutBinding
private val addToGoogleWalletRequestCode = 1000
private lateinit var layout: ActivityCheckoutBinding
private lateinit var addToGoogleWalletButton: View
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Use view binding to access the UI elements
layout = ActivityCheckoutBinding.inflate(layoutInflater)
setContentView(layout.root)
addToGoogleWalletButton = layout.addToGoogleWalletButton
addToGoogleWalletButton.setOnClickListener {
walletClient.savePasses(newObjectJson, this, addToGoogleWalletRequestCode)
}
// Additional logic in your onCreate method
}
Java
import android.os.Bundle;
import android.view.View;
import com.google.android.gms.samples.wallet.databinding.ActivityCheckoutBinding;
private static final int ADD_TO_GOOGLE_WALLET_REQUEST_CODE = 999;
private ActivityCheckoutBinding layout:
private View addToGoogleWalletButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Use view binding to access the UI elements
layout = ActivityCheckoutBinding.inflate(getLayoutInflater());
setContentView(layout.getRoot());
addToGoogleWalletButton = layout.addToGoogleWalletButton;
addToGoogleWalletButton.setOnClickListener(v -> {
walletClient.savePasses(newObjectJson, this, ADD_TO_GOOGLE_WALLET_REQUEST_CODE);
});
// Additional logic in your onCreate method
}
Result handling
The savePasses
method triggers the save flow and invokes the
onActivityResult
method after the save flow has completed. The implementation of onActivityResult
should be similar to the following:
Kotlin
import android.content.Intent
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == addToGoogleWalletRequestCode) {
when (resultCode) {
RESULT_OK -> {
// Pass saved successfully
}
RESULT_CANCELED -> {
// Save operation canceled
}
PayClient.SavePassesResult.SAVE_ERROR -> data?.let { intentData ->
val errorMessage = intentData.getStringExtra(PayClient.EXTRA_API_ERROR_MESSAGE)
// Handle error
}
else -> {
// Handle unexpected (non-API) exception
}
}
}
}
Java
import android.content.Intent;
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ADD_TO_GOOGLE_WALLET_REQUEST_CODE) {
switch (resultCode) {
case RESULT_OK: {
// Pass saved successfully
break;
}
case RESULT_CANCELED: {
// Save operation canceled
break;
}
case PayClient.SavePassesResult.SAVE_ERROR: {
if (data != null) {
String apiErrorMessage = data.getStringExtra(PayClient.EXTRA_API_ERROR_MESSAGE);
// Handle error
}
break;
}
default: {
// Handle unexpected (non-API) exception
}
}
}
}
When the pass is successfully added, the resultCode
contains the value of Activity.RESULT_OK
.