Google Pay国际版开发
一、官网地址(科学上网)
以下是相关的官方文档和链接: - 官方对接文档:[https://developers.google.com/pay/api/android/overview](https://developers.google.com/pay/api/android/overview) - Stripe对接Google Pay:[https://stripe.com/docs/google-pay](https://stripe.com/docs/google-pay) - Stripe验证支付:[https://stripe.com/docs/payments/accept-a-payment?integration=elements](https://stripe.com/docs/payments/accept-a-payment?integration=elements) - Stripe管理后台:[https://dashboard.stripe.com/dashboard](https://dashboard.stripe.com/dashboard)
二、接入流程
三、主要流程
1、服务器请求orderId
2、调用Google Pay
3、通过Stripe完成支付
4、服务器完成验证
四、主要代码实现(1、4主要是服务器流程,以下主要是2、3流程)
项目配置
在build.gradle中添加以下依赖项: ``` implementation 'com.google.android.gms:play-services-wallet:18.1.2' implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.stripe:stripe-android:16.0.1' ``` 在AndroidManifest.xml的application标签下添加以下代码: ```xml ``` 调用Google Pay。```java @RequiresApi(api = Build.VERSION_CODES.N) private void payWithGoogle(double price) { if (paymentsClient == null) { paymentsClient = createPaymentsClient(mActivity); } // 主要是Google Pay一些参数设置 Optional paymentDataRequestJson = createPaymentDataRequest(price); if (!paymentDataRequestJson.isPresent()) { return; } PaymentDataRequest request = PaymentDataRequest.newBuilder() .setTransactionInfo(TransactionInfo.newBuilder() .setTotalPriceStatus(WalletConstants.TOTAL_PRICE_STATUS_FINAL) .setTotalPrice(String.valueOf(price)) .setCurrencyCode(USD) .build()) .build(); } ```@RequiresApi(api = Build.VERSION_CODES.N) private Optional createPaymentDataRequest(double priceCents) { try { JSONObject paymentDataRequest = getBaseRequest(); // Specify one or more payment methods supported by the Google Pay API. paymentDataRequest.put(allowedPaymentMethods, new JSONArray().put(getCardPaymentMethod())); // Detailed information about authorizing the transaction based on whether the user agrees to it. Includes total price and price status. paymentDataRequest.put(transactionInfo, getTransactionInfo(priceCents)); // Merchant information paymentDataRequest.put(merchantInfo, getMerchantInfo()); paymentDataRequest.put(shippingAddressRequired, false); paymentDataRequest.put(emailRequired, false); return Optional.of(paymentDataRequest); } catch (JSONException e) { return Optional.empty(); } } private JSONObject getCardPaymentMethod() throws JSONException { JSONObject cardPaymentMethod = getBaseCardPaymentMethod(); // Set Stripe as the payment method JSONObject tokenizationSpec = new GooglePayConfig(LIVE_API).getTokenizationSpecification();{ apiVersionMinor: 0, apiVersion: 2, paymentMethodData: { description: 中国招商银行 (CMB) •••• 5019, tokenizationData: { type: PAYMENT_GATEWAY, token: {\n \id\: \tok_1HcQIMBcf7rsT369XhdHf1aI\,\n \object\: \token\,\n \card\: {\n \id\: \card_1HcQIMBcf7rsT369lDDy6PIM\,\n \object\: \card\,\n \address_city\: null,\n \”address_country\”: null,\n \”address_line1\”: null,\n \”address_line1_check\”: null,\n \”address_line2\”: null,\ n\ address_state \ : null, n address_zip :null, n address_zip_check :null, n brand : Visa ,public void onCheckResult(int resultCode, Intent data) { switch (resultCode) { case Activity.RESULT_OK: { onGooglePayResult(data); break; } case Activity.RESULT_CANCELED: { errorShowAndRetry(); break; } case AutoResolveHelper.RESULT_ERROR: { final Status status = AutoResolveHelper.getStatusFromIntent(data); errorShowAndRetry(); break; } default: { // Do nothing. } } } private void onGooglePayResult(@NonNull Intent data) { PaymentData paymentData = PaymentData.getFromIntent(data); if (paymentData == null) { errorShowAndRetry(); return; } }/** * 得到PaymentMethodId 去stripe 支付 */ private void paymentGotoStripe(String id){ if ( mStripe != null && !TextUtils.isEmpty(mSecret)) { ConfirmPaymentIntentParams confirmParams = ConfirmPaymentIntentParams.createWithPaymentMethodId(id, mSecret); mStripe.confirmPayment(mActivity, confirmParams); Logger.logE("live pay, click pay ---"); } else if (mStripe == null) { ToastUtils.showSystemToast(R.string.payment_in_progress_tips); Logger.logE("live pay, click pay --- order is null"); } } /** * Google --> stripe--> CallBack * @param requestCode * @param data */ public void paymentResultCallback(int requestCode,Intent data){ mStripe.onPaymentResult(requestCode, data, new PaymentResultCallback(mActivity)); } private final class PaymentResultCallback implements ApiResultCallback<PaymentIntentResult> { @NonNull private final WeakReference<PaymentActivity> activityRef; PaymentResultCallback(@NonNull PaymentActivity activity) { activityRef = new WeakReference<>(activity); } @Override public void onSuccess(@NonNull PaymentIntentResult result) { PaymentActivity activity = activityRef.get(); if (activity == null) { return; } PaymentIntent paymentIntent = result.getIntent(); PaymentIntent.Status status = paymentIntent.getStatus(); if (status == PaymentIntent.Status.Succeeded) { // 后台验证订单 PaymentNetManager.verifyStripeOrder(true,mOrderId, statusData); } else if (status == PaymentIntent.Status.RequiresPaymentMethod) { errorShowAndRetry(); } Logger.logE("live pay, stripe succ, status = " + status); } @Override public void onError(@NonNull Exception e) { PaymentActivity activity = activityRef.get(); if (activity == null) { return; } errorShowAndRetry(); Logger.logE("live pay, stripe succ, error = " + e.getMessage()); } }
五、Google Pay配置
配置地址 https://pay.google.com/business/console/u/2/payment/BCR2DN6TZP4O3TIO
完成Google Pay配置六、完整代码
/** * Description: 国际版Google Pay * --------------------- * Author: xiangpan * Date: 2020/10/14 6:01 PM */public class GooglePayGlobe implements DefaultLifecycleObserver { public static final int LOAD_PAYMENT_DATA_REQUEST_CODE = 5300; public static final String LIVE_API = "pk_test_51Hc6UgKbT4q9TnA8xWZpZwKjXagTRmgyMC5q8HaQqgP1XmiPYRAsLCUMriIoLe5nR2gVtpRY39SeL8x7r00J3duNXzg"; //测试 ENVIRONMENT_TEST 正式 ENVIRONMENT_PRODUCTION public static final int PAYMENTS_ENVIRONMENT = WalletConstants.ENVIRONMENT_TEST; public static final List<String> SUPPORTED_NETWORKS = Arrays.asList( "AMEX", "DISCOVER", "JCB", "MASTERCARD", "VISA"); public static final List<String> SUPPORTED_METHODS = Arrays.asList( "PAN_ONLY", "CRYPTOGRAM_3DS"); public static final String COUNTRY_CODE = "US"; public static final String CURRENCY_CODE = "USD"; public MutableLiveData<StripeDto> statusData = new MutableLiveData<>(); private PaymentActivity mActivity; private PaymentsClient paymentsClient; private Stripe mStripe; private String mOrderId; private String mSecret; private int mCreateOrderRetryTime = 0; private int mVerifyOrderRetryTime = 0; private ChargeUnitDto mChargeUnitDto; private String mCouponUuid; private double mPrice; @RequiresApi(api = Build.VERSION_CODES.N) @Override public void onCreate(@NonNull LifecycleOwner owner) { mActivity = (com.ev.live.payment.PaymentActivity) owner; paymentsClient = createPaymentsClient(mActivity); statusData.observe(mActivity, stripeDto -> { if (stripeDto != null && stripeDto.code == 0) { Logger.logE("live pay stripe, observ " + stripeDto.isFail + " status = " + stripeDto.status); if (stripeDto.status == StripeDto.STRIPE_ORDER_SUCC) { mStripe = new Stripe(mActivity, LIVE_API); mOrderId = stripeDto.orderId; mSecret = stripeDto.client_secret; mPrice = stripeDto.amount; payWithGoogle(mPrice);// AnalyticUtil.firebaseEvent(AnalyticUtil.STRIPE_ORDER_SUCC, getStaticsBundle()); } else if (stripeDto.status == StripeDto.STRIPE_ORDER_FAIL) { if (mCreateOrderRetryTime < 3) { PaymentNetManager.requestStripeOrder(true,mChargeUnitDto.id, mCouponUuid, statusData); }else { stripeDto.status = StripeDto.STRIPE_ORDER_FAIL_FINAL; stripeDto.isFail = true; statusData.postValue(stripeDto); } mCreateOrderRetryTime ++; } else if (stripeDto.status == StripeDto.STRIPE_VERIFY_FAIL) { if (mVerifyOrderRetryTime < 3) { PaymentNetManager.verifyStripeOrder(true,mOrderId, statusData); } mVerifyOrderRetryTime++;// AnalyticUtil.firebaseEvent(AnalyticUtil.STRIPE_VERIFY_FAIL, getStaticsBundle()); } } }); } @Override public void onDestroy(@NonNull LifecycleOwner owner) { mActivity = null; } /** * Google 支付 * @param dto * @param couponUuid */ public void startPayment(ChargeUnitDto dto, String couponUuid) { if (dto != null) { mChargeUnitDto = dto; mCouponUuid = couponUuid; PaymentNetManager.requestStripeOrder(true,mChargeUnitDto.id, mCouponUuid, statusData); }// AnalyticUtil.threeChannelEvent(PAYPAL_ORDER_CLICK, getStaticsBundle()); } private PaymentsClient createPaymentsClient(Activity activity) { Wallet.WalletOptions walletOptions = new Wallet.WalletOptions.Builder().setEnvironment(PAYMENTS_ENVIRONMENT).build(); return Wallet.getPaymentsClient(activity, walletOptions); } @RequiresApi(api = Build.VERSION_CODES.N) private void payWithGoogle( double price) { if (paymentsClient == null) { paymentsClient = createPaymentsClient(mActivity); } Optional<JSONObject> paymentDataRequestJson = createPaymentDataRequest(price); if (!paymentDataRequestJson.isPresent()) { return; } PaymentDataRequest request = PaymentDataRequest.fromJson(paymentDataRequestJson.get().toString()); if (request != null) { if (mActivity!=null){ mActivity.showCircle2Loading(); } AutoResolveHelper.resolveTask( paymentsClient.loadPaymentData(request), mActivity, LOAD_PAYMENT_DATA_REQUEST_CODE ); } } /** * { * "apiVersionMinor": 0, * "apiVersion": 2, * "paymentMethodData": { * "description": "中国招商银行 (CMB) •••• 5019", * "tokenizationData": { * "type": "PAYMENT_GATEWAY", * "token": "{\n \"id\": \"tok_1HcQIMBcf7rsT369XhdHf1\",\n \"object\": \"token\",\n \"card\": {\n \"id\": \"card_1HcQIMBcf7rsT369lDDy6PIM\",\n \"object\": \"card\",\n \"address_city\": null,\n \"address_country\": null,\n \"address_line1\": null,\n \"address_line1_check\": null,\n \"address_line2\": null,\n \"address_state\": null,\n \"address_zip\": null,\n \"address_zip_check\": null,\n \"brand\": \"Visa\",\n \"country\": \"US\",\n \"cvc_check\": null,\n \"dynamic_last4\": \"4242\",\n \"exp_month\": 10,\n \"exp_year\": 2025,\n \"funding\": \"credit\",\n \"last4\": \"5019\",\n \"metadata\": {\n },\n \"name\": \"name\",\n \"tokenization_method\": \"android_pay\"\n },\n \"client_ip\": \"173.194.101.160\",\n \"created\": 1602744638,\n \"livemode\": false,\n \"type\": \"card\",\n \"used\": false\n}\n" * }, * "type": "CARD", * "info": { * "cardNetwork": "VISA", * "cardDetails": "5019" * } * } * } * * @param data * @param resultCode */ public void onCheckResult(int resultCode,Intent data) { switch (resultCode) { case Activity.RESULT_OK: { onGooglePayResult(data); break; } case Activity.RESULT_CANCELED: { errorShowAndRetry(); break; } case AutoResolveHelper.RESULT_ERROR: { final Status status = AutoResolveHelper.getStatusFromIntent(data); errorShowAndRetry(); break; } default: { // Do nothing. } } } private void onGooglePayResult(@NonNull Intent data) { PaymentData paymentData = PaymentData.getFromIntent(data); if (paymentData == null) { errorShowAndRetry(); return; } try { PaymentMethodCreateParams paymentMethodCreateParams = PaymentMethodCreateParams.createFromGooglePay(new JSONObject(paymentData.toJson())); mStripe.createPaymentMethod( paymentMethodCreateParams, new ApiResultCallback<PaymentMethod>() { @Override public void onSuccess(@NonNull PaymentMethod result) { paymentGotoStripe(result.id); } @Override public void onError(@NonNull Exception e) { errorShowAndRetry(); } } ); } catch (Exception e) { errorShowAndRetry(); } } /** * 得到PaymentMethodId 去stripe 支付 */ private void paymentGotoStripe(String id){ if ( mStripe != null && !TextUtils.isEmpty(mSecret)) { ConfirmPaymentIntentParams confirmParams = ConfirmPaymentIntentParams.createWithPaymentMethodId(id, mSecret); mStripe.confirmPayment(mActivity, confirmParams); Logger.logE("live pay, click pay ---"); } else if (mStripe == null) { ToastUtils.showSystemToast(R.string.payment_in_progress_tips); Logger.logE("live pay, click pay --- order is null"); } } /** * Google --> stripe--> CallBack * @param requestCode * @param data */ public void paymentResultCallback(int requestCode,Intent data){ mStripe.onPaymentResult(requestCode, data, new PaymentResultCallback(mActivity)); } /** * 判断用户是否支持Google pay支付 * */ @RequiresApi(api = Build.VERSION_CODES.N) public void possiblyShowGooglePayButton(View view) { if (paymentsClient == null) { paymentsClient = createPaymentsClient(mActivity); } final Optional<JSONObject> isReadyToPayJson = getIsReadyToPayRequest(); if (!isReadyToPayJson.isPresent()) { return; } IsReadyToPayRequest request = IsReadyToPayRequest.fromJson(isReadyToPayJson.get().toString()); Task<Boolean> task = paymentsClient.isReadyToPay(request); task.addOnCompleteListener(mActivity, new OnCompleteListener<Boolean>() { @Override public void onComplete(@NonNull Task<Boolean> task) { if (task.isSuccessful()) { if (task.getResult()) { view.setVisibility(View.VISIBLE); } else { view.setVisibility(View.GONE); } } else { view.setVisibility(View.GONE); Log.w("isReadyToPay failed", task.getException()); } } }); } @RequiresApi(api = Build.VERSION_CODES.N) private Optional<JSONObject> createPaymentDataRequest(double priceCents) { try { JSONObject paymentDataRequest = getBaseRequest(); // 指定是否支持 Google Pay API 所支持的一种或多种付款方式。 paymentDataRequest.put("allowedPaymentMethods", new JSONArray().put(getCardPaymentMethod())); // 有关根据用户是否同意交易来为交易授权的详细信息。包含总价和价格状态 paymentDataRequest.put("transactionInfo", getTransactionInfo(priceCents)); //商家信息 paymentDataRequest.put("merchantInfo", getMerchantInfo()); paymentDataRequest.put("shippingAddressRequired", false); paymentDataRequest.put("emailRequired", false); return Optional.of(paymentDataRequest); } catch (JSONException e) { return Optional.empty(); } } private JSONObject getCardPaymentMethod() throws JSONException { JSONObject cardPaymentMethod = getBaseCardPaymentMethod(); JSONObject tokenizationSpec = new GooglePayConfig(LIVE_API).getTokenizationSpecification(); cardPaymentMethod.put("tokenizationSpecification", tokenizationSpec); return cardPaymentMethod; } /** * 金钱信息 */ private JSONObject getTransactionInfo(double price) throws JSONException { JSONObject transactionInfo = new JSONObject(); transactionInfo.put("totalPrice", price+""); transactionInfo.put("totalPriceStatus", "FINAL"); transactionInfo.put("countryCode", COUNTRY_CODE); transactionInfo.put("currencyCode", CURRENCY_CODE); transactionInfo.put("checkoutOption", "COMPLETE_IMMEDIATE_PURCHASE"); return transactionInfo; } /** * 商家信息 * merchantId 商家Id */ private JSONObject getMerchantInfo() throws JSONException { return new JSONObject().put("merchantName", "Guruji").put("merchantId", "BCR2DN6T4XFIT7KA"); } @RequiresApi(api = Build.VERSION_CODES.N) private Optional<JSONObject> getIsReadyToPayRequest() { try { JSONObject isReadyToPayRequest = getBaseRequest(); isReadyToPayRequest.put( "allowedPaymentMethods", new JSONArray().put(getBaseCardPaymentMethod())); isReadyToPayRequest.put("existingPaymentMethodRequired", true); return Optional.of(isReadyToPayRequest); } catch (JSONException e) { return Optional.empty(); } } private JSONObject getBaseCardPaymentMethod() throws JSONException { JSONObject cardPaymentMethod = new JSONObject(); cardPaymentMethod.put("type", "CARD"); JSONObject parameters = new JSONObject(); parameters.put("allowedAuthMethods", getAllowedCardAuthMethods()); parameters.put("allowedCardNetworks", getAllowedCardNetworks()); // Optionally, you can add billing address/phone number associated with a CARD payment method. parameters.put("billingAddressRequired", false); cardPaymentMethod.put("parameters", parameters); return cardPaymentMethod; } private JSONArray getAllowedCardAuthMethods() { return new JSONArray(SUPPORTED_METHODS); } private JSONArray getAllowedCardNetworks() { return new JSONArray(SUPPORTED_NETWORKS); } private JSONObject getBaseRequest() throws JSONException { return new JSONObject() .put("apiVersion", 2) .put("apiVersionMinor", 0); } private Bundle getStaticsBundle() { Bundle bundle = new Bundle(); if (!TextUtils.isEmpty(mOrderId)) { bundle.putString("order_id", mOrderId); } return bundle; } private void errorShowAndRetry () { StripeDto stripeDto = new StripeDto(); stripeDto.isFail = true; stripeDto.status = StripeDto.STRIPE_PAY_FAIL; statusData.setValue(stripeDto); } private final class PaymentResultCallback implements ApiResultCallback<PaymentIntentResult> { @NonNull private final WeakReference<PaymentActivity> activityRef; PaymentResultCallback(@NonNull PaymentActivity activity) { activityRef = new WeakReference<>(activity); } @Override public void onSuccess(@NonNull PaymentIntentResult result) { PaymentActivity activity = activityRef.get(); if (activity == null) { return; } PaymentIntent paymentIntent = result.getIntent(); PaymentIntent.Status status = paymentIntent.getStatus(); if (status == PaymentIntent.Status.Succeeded) { PaymentNetManager.verifyStripeOrder(true,mOrderId, statusData); } else if (status == PaymentIntent.Status.RequiresPaymentMethod) { errorShowAndRetry(); } Logger.logE("live pay, stripe succ, status = " + status); } @Override public void onError(@NonNull Exception e) { PaymentActivity activity = activityRef.get(); if (activity == null) { return; } errorShowAndRetry(); Logger.logE("live pay, stripe succ, error = " + e.getMessage()); } }}
希望可以帮助遇到同样问题的你😁😁😁😁
如有建议和意见,请及时沟通。
还木有评论哦,快来抢沙发吧~