Last active
December 26, 2024 13:48
-
-
Save krunk4ever/79cdc15d2e09b15a5826d9d98c2c3dda to your computer and use it in GitHub Desktop.
PaymentDataRequest support for Google Pay API v2 on Android
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.os.Bundle | |
import com.google.android.gms.wallet.PaymentData | |
import com.google.android.gms.wallet.PaymentDataRequest | |
import com.google.android.gms.wallet.PaymentMethodTokenizationParameters | |
import com.google.android.gms.wallet.WalletConstants | |
import org.json.JSONArray | |
import org.json.JSONObject | |
/** | |
* Google Pay API request configurations. | |
* | |
* @see [Google Pay API Android | |
* documentation](https://developers.google.com/pay/api/android/) | |
*/ | |
object GooglePay { | |
/** | |
* Create a Google Pay API base request object with properties used in all requests. | |
* | |
* @return Google Pay API base request object | |
*/ | |
private val baseRequest: JSONObject | |
get() = JSONObject() | |
.put("apiVersion", 2) | |
.put("apiVersionMinor", 0) | |
/** | |
* Identify your gateway and your app's gateway merchant identifier. | |
* | |
* The Google Pay API response will return an encrypted payment method capable of being charged | |
* by a supported gateway after payer authorization. | |
* | |
* @return payment data tokenization for the CARD payment method | |
* @see [PaymentMethodTokenizationSpecification](https://developers.google.com/pay/api/android/reference/object.PaymentMethodTokenizationSpecification) | |
*/ | |
private fun tokenizationSpecification(tokenizationParameters: PaymentMethodTokenizationParameters): JSONObject { | |
val tokenizationSpecification = JSONObject() | |
.put("type", "PAYMENT_GATEWAY") | |
// inject all the token parameters into json object | |
tokenizationParameters.parameters?.let { bundle -> | |
tokenizationSpecification.put("parameters", bundle.toJSONObject()) | |
} | |
return tokenizationSpecification | |
} | |
/** | |
* Card networks supported by your app and your gateway. | |
* | |
* @return allowed card networks | |
* @see [CardParameters](https://developers.google.com/pay/api/android/reference/object.CardParameters) | |
*/ | |
private fun allowedCardNetworks(allowedCardNetworkIDs: Collection<Int>): JSONArray { | |
return JSONArray(allowedCardNetworkIDs.mapNotNull { cardNetworkName(it) }) | |
} | |
private fun cardNetworkName(cardNetworkID: Int): String? { | |
return when (cardNetworkID) { | |
WalletConstants.CARD_NETWORK_AMEX -> "AMEX" | |
WalletConstants.CARD_NETWORK_DISCOVER -> "DISCOVER" | |
WalletConstants.CARD_NETWORK_JCB -> "JCB" | |
WalletConstants.CARD_NETWORK_MASTERCARD -> "MASTERCARD" | |
WalletConstants.CARD_NETWORK_VISA -> "VISA" | |
WalletConstants.CARD_NETWORK_INTERAC -> "INTERAC" | |
WalletConstants.CARD_NETWORK_OTHER -> "OTHER" | |
else -> null | |
} | |
} | |
/** | |
* Card authentication methods supported by your app and your gateway. | |
* | |
* @return allowed card authentication methods | |
* @see [CardParameters](https://developers.google.com/pay/api/android/reference/object.CardParameters) | |
*/ | |
private fun allowedCardAuthMethods(allowedCardAuthMethodIDs: Collection<Int>): JSONArray { | |
return JSONArray(allowedCardAuthMethodIDs.mapNotNull { allowedCardAuthMethodName(it) }) | |
} | |
private fun allowedCardAuthMethodName(allowedCardAuthMethodID: Int): String? { | |
return when (allowedCardAuthMethodID) { | |
WalletConstants.PAYMENT_METHOD_CARD -> "PAN_ONLY" | |
WalletConstants.PAYMENT_METHOD_TOKENIZED_CARD -> "CRYPTOGRAM_3DS" | |
else -> null | |
} | |
} | |
/** | |
* Describe your app's support for the CARD payment method. | |
* | |
* The provided properties are applicable to both an IsReadyToPayRequest and a | |
* PaymentDataRequest. | |
* | |
* @return a CARD PaymentMethod object describing accepted cards | |
* @see [PaymentMethod](https://developers.google.com/pay/api/android/reference/object.PaymentMethod) | |
*/ | |
private fun baseCardPaymentMethod( | |
allowedCardNetworkIDs: Collection<Int>, | |
allowedCardAuthMethodIDs: Collection<Int>, | |
billingAddressParameters: JSONObject? | |
): JSONObject { | |
val parameters = JSONObject() | |
.put("allowedAuthMethods", allowedCardAuthMethods(allowedCardAuthMethodIDs)) | |
.put("allowedCardNetworks", allowedCardNetworks(allowedCardNetworkIDs)) | |
billingAddressParameters?.let { | |
parameters.put("billingAddressRequired", true) | |
parameters.put("billingAddressParameters", it) | |
} | |
val cardPaymentMethod = JSONObject() | |
.put("type", "CARD") | |
.put("parameters", parameters) | |
return cardPaymentMethod | |
} | |
/** | |
* Describe the expected returned payment data for the CARD payment method. | |
* | |
* @return a CARD PaymentMethod describing accepted cards and optional fields | |
* @see [PaymentMethod](https://developers.google.com/pay/api/android/reference/object.PaymentMethod) | |
*/ | |
fun cardPaymentMethod( | |
tokenizationParameters: PaymentMethodTokenizationParameters, | |
allowedCardNetworkIDs: Collection<Int>, | |
allowedCardAuthMethodIDs: Collection<Int>, | |
billingAddressParameters: JSONObject? = null | |
): JSONObject { | |
val cardPaymentMethod = baseCardPaymentMethod(allowedCardNetworkIDs, allowedCardAuthMethodIDs, billingAddressParameters) | |
.put("tokenizationSpecification", tokenizationSpecification(tokenizationParameters)) | |
return cardPaymentMethod | |
} | |
/** | |
* Provide Google Pay API with a payment amount, currency, and amount status. | |
* | |
* @return information about the requested payment | |
* @see [TransactionInfo](https://developers.google.com/pay/api/android/reference/object.TransactionInfo) | |
*/ | |
fun transactionInfo(price: String, currency: String, priceStatusID: Int): JSONObject { | |
val transactionInfo = JSONObject() | |
.put("totalPrice", price) | |
.put("currencyCode", currency) | |
priceStatusName(priceStatusID)?.let { | |
transactionInfo.put("totalPriceStatus", it) | |
} | |
return transactionInfo | |
} | |
private fun priceStatusName(priceStatusID: Int): String? { | |
return when (priceStatusID) { | |
WalletConstants.TOTAL_PRICE_STATUS_NOT_CURRENTLY_KNOWN -> "NOT_CURRENTLY_KNOWN" | |
WalletConstants.TOTAL_PRICE_STATUS_ESTIMATED -> "ESTIMATED" | |
WalletConstants.TOTAL_PRICE_STATUS_FINAL -> "FINAL" | |
else -> null | |
} | |
} | |
/** | |
* Information about the merchant requesting payment information. | |
* | |
* @return information about the merchant | |
* @see [MerchantInfo](https://developers.google.com/pay/api/android/reference/object.MerchantInfo) | |
*/ | |
fun merchantInfo(merchantName: String): JSONObject { | |
return JSONObject() | |
.put("merchantName", merchantName) | |
} | |
fun billingAddressParameters(billingAddressFormatID: Int, phoneNumberRequired: Boolean): JSONObject { | |
val billingAddressParameters = JSONObject() | |
.put("phoneNumberRequired", phoneNumberRequired) | |
billingAddressFormatName(billingAddressFormatID)?.let { | |
billingAddressParameters.put("format", it) | |
} | |
return billingAddressParameters | |
} | |
private fun billingAddressFormatName(billingAddressFormatID: Int): String? { | |
return when (billingAddressFormatID) { | |
WalletConstants.BILLING_ADDRESS_FORMAT_MIN -> "MIN" | |
WalletConstants.BILLING_ADDRESS_FORMAT_FULL -> "FULL" | |
else -> null | |
} | |
} | |
/** | |
* An object describing information requested in a Google Pay payment sheet. | |
* | |
* @return payment data expected by your app | |
* @see [PaymentDataRequest](https://developers.google.com/pay/api/android/reference/object.PaymentDataRequest) | |
*/ | |
fun paymentDataRequest( | |
cardPaymentMethod: JSONObject, | |
transactionInfo: JSONObject, | |
merchantInfo: JSONObject | |
): PaymentDataRequest { | |
val paymentDataRequest = baseRequest | |
.put("allowedPaymentMethods", JSONArray().put(cardPaymentMethod)) | |
.put("transactionInfo", transactionInfo) | |
.put("merchantInfo", merchantInfo) | |
return PaymentDataRequest.fromJson(paymentDataRequest.toString()) | |
} | |
} | |
fun PaymentData.billingAddressCountryCode(): String? { | |
// when you create PaymentData from intent/json, cardInfo and billingAddress are no longer populated | |
return cardInfo?.billingAddress?.countryCode | |
?: JSONObject(toJson()) | |
.optJSONObject("paymentMethodData") | |
.optJSONObject("info") | |
.optJSONObject("billingAddress") | |
.optString("countryCode") | |
} | |
fun PaymentData.billingAddressPostalCode(): String? { | |
// when you create PaymentData from intent/json, cardInfo and billingAddress are no longer populated | |
return cardInfo?.billingAddress?.postalCode | |
?: JSONObject(toJson()) | |
.optJSONObject("paymentMethodData") | |
.optJSONObject("info") | |
.optJSONObject("billingAddress") | |
.optString("postalCode") | |
} | |
fun Bundle.toJSONObject(): JSONObject { | |
val jsonObject = JSONObject() | |
keySet().forEach { key -> | |
getString(key)?.let { value -> | |
jsonObject.put(key, value) | |
} | |
} | |
return jsonObject | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.braintreepayments.api.BraintreeFragment; | |
import com.braintreepayments.api.GooglePayment; | |
import com.braintreepayments.api.interfaces.BraintreeResponseListener; | |
import com.google.android.gms.wallet.AutoResolveHelper; | |
import com.google.android.gms.wallet.PaymentData; | |
import com.google.android.gms.wallet.PaymentDataRequest; | |
import com.google.android.gms.wallet.PaymentsClient; | |
import com.google.android.gms.wallet.Wallet; | |
import com.google.android.gms.wallet.WalletConstants; | |
import org.json.JSONObject; | |
public class GooglePaymentClient implements GooglePaymentApi { | |
private final PaymentsClient googlePaymentsClient; | |
@Override | |
public void loadGooglePay(String formattedPrice, int requestCode) { | |
JSONObject billingAddressParameters = GooglePay.INSTANCE.billingAddressParameters(WalletConstants.BILLING_ADDRESS_FORMAT_MIN, false); | |
JSONObject cardPaymentMethod = GooglePay.INSTANCE.cardPaymentMethod( | |
parameters, | |
allowedCardNetworks, | |
Arrays.asList(WalletConstants.PAYMENT_METHOD_CARD, WalletConstants.PAYMENT_METHOD_TOKENIZED_CARD), | |
billingAddressParameters); | |
JSONObject transactionInfo = GooglePay.INSTANCE.transactionInfo( | |
formattedPrice, | |
currencyFormatter.getLocalCurrencyString(), | |
WalletConstants.TOTAL_PRICE_STATUS_ESTIMATED); | |
JSONObject merchantInfo = GooglePay.INSTANCE.merchantInfo( | |
braintreeFragment.getContext().getString(R.string.merchant_name) | |
); | |
PaymentDataRequest paymentDataRequest = GooglePay.INSTANCE.paymentDataRequest( | |
cardPaymentMethod, | |
transactionInfo, | |
merchantInfo); | |
AutoResolveHelper.resolveTask( | |
googlePaymentsClient.loadPaymentData(paymentDataRequest), | |
activity, | |
requestCode); | |
} | |
@Override | |
public void tokenizeGooglePayment(PaymentData paymentData) { | |
GooglePayment.tokenize(braintreeFragment, paymentData); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment