Implementation
Sequence Diagram
Requirements
Before starting implementation you should have completed Installation of the MPP (Mea Push Provisioning) SDK.
Main Interface
Initialize
To begin Issuer app should initialize MeaPushProvisioning instance.
if (!MeaPushProvisioning.isInitialized()) {
MeaPushProvisioning.initialize(this);
}
Card Data Parameters
Push provisioning flow is started by initializing MppCardDataParameters
object with CardId
, CardSecret
or EncryptedPan
. After initializing card data parameters push provisioning can be started with push card method.
CardId & CardSecret
String cardId = "<value>";
String cardSecret = "<value>";
MppCardDataParameters cardParams = MppCardDataParameters.withCardSecret(cardId, cardSecret);
EncryptedCardData
String encryptedCardData = "<value>";
String publicKeyFingerprint = "<value>";
String encryptedKey = "<value>";
String initialVector = "<value>";
MppCardDataParameters cardParams = MppCardDataParameters.withEncryptedPan(encryptedCardData,
publicKeyFingerprint,
encryptedKey,
initialVector);
INFO
Guide for
encryptedCardData
generation can be found in Card Data Encryption manual.
Loading Configuration
By default MPP SDK is loading mea_config
configuration file, however a custom name can be used. When defining a custom name for the configuration file use MeaPushProvisioning.Configuration.loadConfig(String)
to load the configuration. Configuration file should be placed in application resources res/raw
folder.
MeaPushProvisioning.Configuration.loadConfig("custom_config_name");
INFO
MPP SDK throws
MppException
if configuration file is missing, broken or otherwise fails to load.
GooglePay Interface
MeaPushProvisioning.GooglePay helper interface provides methods to interact with Google Pay wallet.
Google Pay Push Provisioning API documentation:
- Google TapAndPay
- Google Pay Issuers Guide
- Android Push Provisioning
- Google Pay Push Provisioning API
❇️ Useful Information
(Only authorized Google accounts can view this content.
)
If you have multiple Google accounts and you can not open link with yours specific one, then just try to add?authuser=1
OR&authuser=1
to end of link. You may change1
to any index of your account. Example:https://developers.google.com/pay/issuers/apis/push-provisioning/android/whitelisting?authuser=3
Push Card
When MPP SDK is initialized, Issuer app can push provision card using MeaPushProvisioning.GooglePay.pushCard(...)
and MppCardDataParameters
. This method checks the state of Google Pay wallet and creates a new instance when necessary. Backend generated opaque payment card (OPC) is received, and if the specific card is not added to Google Pay wallet already, it pushes the card to the Google Pay wallet via Google Push Provisioning API.
MeaPushProvisioning.GooglePay.pushCard(cardParams, "card display name", userAddress, getActivity(), new MppPushCardToGooglePayListener() {
@Override
public void onSuccess(String tokenReferenceId, String cardLastFourDigits, MppPaymentNetwork cardNetwork) {
...
}
@Override
public void onFailure(MppError mppError, int tapAndPayStatusCode) {
...
}
});
Handle Google Pay Result Callbacks
Google Pay push provisioning results are returned through Activity.onActivityResult(int, int, Intent)
method. Application should forward these intermediate results to the MeaPushProvisioning.GooglePay.handlePushCardOnActivityResult(int, int, Intent, Activity)
method. Final result of push provisioning is returned returned to MppPushCardToGooglePayListener
callback.
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (MeaPushProvisioning.GooglePay.handleOnActivityResult(requestCode, resultCode, data, this)) {
// Handled by MPP SDK, no action needed.
} else {
// Optionaly handle results for other request codes.
}
}
Add to Google Pay Button
The Add to Google Pay button is used exclusively to initiate the Google Pay card provisioning flow from an Issuer app.
The "Add to Google Pay" are available as resizable bitmaps (NinePatch files) suitable for including in your layout: Google Pay Brand guidelines - Assets
Note: Using
Flutter
,React Native
or another cross-platform app development framework? Check out Flutter-specific instructions here.
Show or Hide Add to Google Pay Button
App is responsible to check and decide if "Add to Google Pay" should be shown or hidden for the user. Button should be shown only when card is not added to Google Pay already.
MPP SDK provides the following methods to check if the specific card is already added to Google Pay wallet:
MeaPushProvisioning.GooglePay.checkWalletForCardSuffix(String cardSuffix, GooglePayRegisteredTokensListener listener)
- using card suffix, does not require network connection.MeaPushProvisioning.GooglePay.checkWalletForToken(MppPaymentNetwork paymentNetwork, String tokenId, GooglePayTokenListener listener)
- using pre-fetched token data, does not require network connection.MeaPushProvisioning.GooglePay.checkWalletForCardToken(MppCardDataParameters cardData, GooglePayTokenListener listener)
- using card data, requires network connection.
Example:
MppCardDataParameters cardParams = MppCardDataParameters.withCardSecret(cardId, cardSecret);
MeaPushProvisioning.GooglePay.checkWalletForCardToken(
cardParams,
new GooglePayTokenListener() {
@Override
public void onSuccess(@NonNull GooglePayTokenInfo googlePayTokenInfo) {
...
String tokenId = googlePayTokenInfo.getTokenId();
Boolean isTokenStateNeedIdentityVerification = googlePayTokenInfo.getTokenState() == GooglePayTokenState.TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION;
}
@Override
public void onFailure(@NonNull MppError mppError) {
...
}
}
);
If the card exists in Google Pay wallet, these methods return a single item or a list of GooglePayTokenInfo
items that contains information about the specific Google Pay token, use getTokenId()
, getTokenState()
, getPaymentNetwork()
and isSelectedAsDefault()
methods to get the values.
Issuer app should hide "Add to Google Pay" button when card exists in Google Pay wallet. If methods above return null
, Issuer app should show "Add to Google Pay" button.
Use GooglePayTokenInfo.getTokenState()
to get additional info about the token state.
Managing Default NFC Payment App
Getting Registered Tokens from Google Pay Wallet
There might be some use cases when Issuer app needs to get all registered tokens from Google Pay wallet, for example, yellow path use case. Method MeaPushProvisioning.GooglePay.getRegisteredTokens(...)
returns list of TokenInfo
items related to the active wallet.
MeaPushProvisioning.GooglePay.getRegisteredTokens(new GooglePayRegisteredTokensListener() {
@Override
public void onSuccess(List<TokenInfo> tokenList) {
// Iterate list.
}
@Override
public void onFailure(MppError error) {
// Handle error.
}
});
Example how to find specific card by last 4 digits:
String cardLastFourDigits = "1234";
MeaPushProvisioning.GooglePay.getRegisteredTokens(new GooglePayRegisteredTokensListener() {
@Override
public void onSuccess(List<TokenInfo> tokenList) {
for (TokenInfo tokenInfo : tokenList) {
// Find matching card based on the last 4 digits.
if (cardLastFourDigits.equals(tokenInfo.getFpanLastFour())) {
GooglePayTokenState tokenState = GooglePayTokenState.getTokenState(tokenInfo.getTokenState());
MppPaymentNetwork paymentNetwork = MppPaymentNetwork.getPaymentNetwork(tokenInfo.getNetwork());
GooglePayTokenInfo googlePayTokenInfo = new GooglePayTokenInfo(tokenInfo.getIssuerTokenId(), tokenState, paymentNetwork, tokenInfo.getIsDefaultToken());
String tokenId = googlePayTokenInfo.getTokenId();
Boolean isTokenStateNeedIdentityVerification = googlePayTokenInfo.getTokenState() == GooglePayTokenState.TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION;
break;
}
}
}
@Override
public void onFailure(MppError error) {
...
}
});
Continuing Yellow Path Through Push Provisioning
Issuer app should allow users to continue yellow path through push provisioning.
Issuer app should get the token of the selected card and check the token state. If token state matches value TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION
, card provisioning has entered yellow path. Once matching GooglePayTokenInfo
is available, use MeaPushProvisioning.GooglePay.tokenize(GooglePayTokenInfo, String, Activity, GooglePayTokenizeListener)
for continuing provisioning.
In general GooglePayTokenInfo
of the card can be fetched using MeaPushProvisioning.GooglePay.checkWalletForCardToken(...)
, however for some issuers or processors backend only provides active tokens and does not provide pending tokens that have entered yellow path. See sections below for each of the cases.
Pending Tokens Available via Backend
After finding card with MeaPushProvisioning.GooglePay.checkWalletForCardToken(MppCardDataParameters cardData, GooglePayTokenListener listener)
in Google Pay wallet, check the state of the token. If token state matches TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION
, card push provisioning has entered yellow path and requires additional user authentication.
Show "Add to Google Pay" button and call MeaPushProvisioning.GooglePay.tokenize(GooglePayTokenInfo, String, Activity, GooglePayTokenizeListener)
to continue push provisioning, when the button is tapped.
MeaPushProvisioning.GooglePay.checkWalletForCardToken(cardDataParameters, new GooglePayTokenListener() {
@Override
public void onSuccess(@NonNull GooglePayTokenInfo googlePayTokenInfo) {
if (googlePayTokenInfo.getTokenState() == GooglePayTokenState.TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION) {
// Card token requires additional user authentication for yellow path, show Add to Google Pay button.
// When tapping button, call MeaPushProvisioning.GooglePay.tokenize(googlePayTokenInfo, ...).
}
else {
// Token already exists in Google Pay wallet and no action required from Issuer app, hide Add to Google Pay button.
}
}
@Override
public void onFailure(@NonNull MppError mppError) {
// Card token not found in Google Pay wallet, show Add to Google Pay button.
// When tapping button, call MeaPushProvisioning.GooglePay.pushCard(...).
}
});
Pending Tokens Not Available via Backend
Use MeaPushProvisioning.GooglePay.getRegisteredTokens(...)
to get all tokens provisioned in Google Pay wallet. Iterate all the TokenInfo
entities and match the selected card based on the last four digits. Once a matching token is found, check the state of the token. If token state matches TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION
, card push provisioning has entered yellow path and requires additional user authentication.
Show "Add to Google Pay" button and call MeaPushProvisioning.GooglePay.tokenize(GooglePayTokenInfo, String, Activity, GooglePayTokenizeListener)
to continue push provisioning, when the button is tapped.
MeaPushProvisioning.GooglePay.getRegisteredTokens(new GooglePayRegisteredTokensListener() {
@Override
public void onSuccess(@NonNull List<TokenInfo> tokenList) {
for (TokenInfo tokenInfo : tokenList) {
// Find matching card based on the last four digits.
if (CARD_LAST_FOUR_DIGITS.equals(tokenInfo.getFpanLastFour())) {
GooglePayTokenState tokenState = GooglePayTokenState.getTokenState(tokenInfo.getTokenState());
if (tokenState == GooglePayTokenState.TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION) {
// Card token requires additional user authentication for yellow path, show Add to Google Pay button.
// When tapping button, call MeaPushProvisioning.GooglePay.tokenize(googlePayTokenInfo, ...).
MppPaymentNetwork paymentNetwork = MppPaymentNetwork.getPaymentNetwork(tokenInfo.getNetwork());
GooglePayTokenInfo googlePayTokenInfo = new GooglePayTokenInfo(tokenInfo.getIssuerTokenId(), tokenState, paymentNetwork, tokenInfo.getIsDefaultToken());
}
else {
// Hide Add to Google Pay button.
}
break;
}
}
}
@Override
public void onFailure(@NonNull MppError error) {
// Handle error.
}
});
Alternatively, use MeaPushProvisioning.GooglePay.checkWalletForCardSuffix(cardSuffix, listener)
to get token(s) with matching PAN suffix.
MeaPushProvisioning.GooglePay.checkWalletForCardSuffix(CARD_LAST_FOUR_DIGITS, new GooglePayRegisteredTokensListener() {
@Override
public void onSuccess(@NonNull List<TokenInfo> tokenInfoList) {
for (TokenInfo tokenInfo : tokenInfoList) {
GooglePayTokenState tokenState = GooglePayTokenState.getTokenState(tokenInfo.getTokenState());
if (tokenState == GooglePayTokenState.TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION) {
// Card token requires additional user authentication for yellow path, show Add to Google Pay button.
// When tapping button, call MeaPushProvisioning.GooglePay.tokenize(googlePayTokenInfo, ...).
MppPaymentNetwork paymentNetwork = MppPaymentNetwork.getPaymentNetwork(tokenInfo.getNetwork());
GooglePayTokenInfo googlePayTokenInfo = new GooglePayTokenInfo(tokenInfo.getIssuerTokenId(), tokenState, paymentNetwork, tokenInfo.getIsDefaultToken());
} else {
// Hide Add to Google Pay button.
}
}
}
@Override
public void onFailure(@NonNull MppError mppError) {
// Handle error
}
});
Using Tokenize
INFO
You should have implemented Handling Google Pay Result Callbacks.
// When Add to Google Pay button tapped AND card token requires additional user authentication for yellow path.
MeaPushProvisioning.GooglePay.tokenize(googlePayTokenInfo, "card name", getActivity(), new GooglePayTokenizeListener() {
@Override
public void onSuccess() {
...
}
@Override
public void onFailure(@NonNull MppError mppError) {
...
}
});
App-to-App Verification with Activation Code
Handle Google Pay Data Changed Events
Registering for data changed events allows an issuer app to re-query information about their digitized cards whenever the user makes a change in Google Pay wallet.
MPP SDK will immediately call an issuer app callback whenever the following events occur:
- The active wallet changes (by changing the active account);
- The selected card of the active wallet changes;
- Tokenized cards are added or removed from the active wallet;
- The status of a token in the active wallet changes.
INFO
GooglePayDataChangedListener
Only foreground applications are notified of the data changed events. Therefore, each application should update the token statuses not only by receivingGooglePayDataChangedListener
, but also when the application launches or returns to the foreground.
Register listener:
GooglePayDataChangedListener listener = new GooglePayDataChangedListener() {
@Override
public void onDataChanged() {
// Reload data in UI.
}
};
MeaPushProvisioning.GooglePay.registerDataChangedListener(listener);
Stop listening data changed events by removing GooglePayDataChangedListener
:
MeaPushProvisioning.GooglePay.removeDataChangedListener(listener);
Testing in Sandbox Mode
By default, Google Pay works in production mode with real payments. During development and pre-production testing you can reconfigure Google Pay to work in sandbox mode by placing a special file on your device. Once connected to sandbox, requests will be routed to Google's sandbox environment which connects to the TSP's sandbox environment.
Working in sandbox mode: Google Pay sandbox mode
Use adb command to toggle sandbox mode. To turn sandbox mode on, add an empty file and reboot:
$ adb shell touch /sdcard/Download/android_pay_env_override_sandbox
$ adb reboot
To switch back to production mode, delete the file and reboot the device:
$ adb shell rm /sdcard/Download/android_pay_env_override_sandbox
$ adb reboot
References
Updated about 1 year ago