欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

谷歌支付访问流程 + 无需实际支付

最编程 2024-04-29 15:03:37
...

google pay的api超级简单,基本上所有的流程都可以在客户端完成,正因为这样,更容易带来一些问题。

官方文档地址戳这里

一.接入前准备

##   1.申请一个google play开发者账号,需要支付25美金
##   2.提前准备好一个apk(不需要集成支付sdk,占位用),在google play控制台上传你的apk
##   3.发布一个alpha或者beta的版本,发布之前需要点亮以下选项(提交商品详情内容)(确定内容分级)(选择发布范围)等,之后才能正常发布
##   4.添加测试人员,等应用审核通过之后,会得到一个地址,把地址发给对方,让对方点击同意加入测试即可,测试地址;
	https://play.google.com/apps/testing/xxx    xxx是你应用的包名
##   5.需要创建应用内商品(商品id,商品描述,定价),按提示填就可以了

##注:一定要等你的应用为Published状态之后,在app里面才能查到商品id,执行支付等操作,否则怎么样都查不到

二.集成步骤

## 目前已经升级到V3版本,AIDL的方法已经过时了,并且未来的版本会将之移除,推荐使用使用 Google Play 结算库

1.添加依赖

implementation 'com.android.billingclient:billing:2.0.1'

2.添加权限

<uses-permission android:name="com.android.vending.BILLING" />

3.建立连接

mBillingClient = BillingClient.newBuilder(this.mActivity).enablePendingPurchases().setListener(this).build();
    mBillingClient.startConnection(new BillingClientStateListener() {
        @Override
        public void onBillingSetupFinished(BillingResult billingResult) {
            Log.e(TAG, "onBillingSetupFinished code = " + billingResult.getResponseCode() + " ,  msg = " + billingResult.getDebugMessage());
            if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {

            }
        }

        @Override
        public void onBillingServiceDisconnected() {

        }
    });

4.查询商品信息

private void queryPurchases(@NonNull final String purchaseId) {
    if (!isClientInit()) {
        if (mListener != null) {
            mListener.onError();
        }
        return;
    }
    List<String> skuList = new ArrayList<>();
    skuList.add(purchaseId);
    skuList.add("xxx");  // 这个参数不能为空,值随便传
    SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
    params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
    mBillingClient.querySkuDetailsAsync(params.build(),
            new SkuDetailsResponseListener() {
                @Override
                public void onSkuDetailsResponse(BillingResult billingResult,
                                                 List<SkuDetails> skuDetailsList) {
                    Log.e(TAG, "onSkuDetailsResponse code = " + billingResult.getResponseCode() + " ,  msg = " + billingResult.getDebugMessage() + " , skuDetailsList = " + skuDetailsList);
                    // Process the result.
                    if (skuDetailsList == null || skuDetailsList.isEmpty()) {
                        if (mListener != null) {
                            mListener.onError();
                        }
                        return;
                    }
                    SkuDetails skuDetails = null;
                    for (SkuDetails details : skuDetailsList) {
                        Log.e(TAG, "onSkuDetailsResponse skuDetails = " + details.toString());
                        if (purchaseId.equals(details.getSku())) {
                            skuDetails = details;
                        }
                    }
                    if (skuDetails != null) {
                        pay(skuDetails);
                    } else {
                        if (mListener != null) {
                            mListener.onError();
                        }
                    }
                }
            });
}

5.执行真正的pay操作

BillingFlowParams flowParams = BillingFlowParams.newBuilder()
                .setSkuDetails(details)
                .build();
        int code = mBillingClient.launchBillingFlow(mActivity, flowParams).getResponseCode();

6.支付回调

还记得前面mBillingClient = BillingClient.newBuilder(this.mActivity).enablePendingPurchases().setListener(this)这个操作吗,这个this也是一个监听器,代表的是支付的回调:
@Override
public void onPurchasesUpdated(BillingResult billingResult, @Nullable List<Purchase> purchases) {
    Log.e(TAG, "onPurchasesUpdated code = " + billingResult.getResponseCode() + " ,  msg = " + billingResult.getDebugMessage());
    if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK
            && purchases != null) {
        if (mListener != null) {
            mListener.onSuccess();
        }
        for (Purchase purchase : purchases) {
            handlePurchase(purchase, true);
        }
    } else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) {
        // Handle an error caused by a user cancelling the purchase flow.
        if (mListener != null) {
            mListener.onCancel();
        }
    } else {
        // Handle any other error codes.
        if (mListener != null) {
            mListener.onError();
        }
    }
}

7.支付成功之后需要处理订购信息

// 只有消费成功之后,才能真正到账,否则3天之后,会执行退款处理 测试阶段只有5分钟
        mBillingClient.consumeAsync(ConsumeParams.newBuilder()
                        .setDeveloperPayload(purchase.getDeveloperPayload())
                        .setPurchaseToken(purchase.getPurchaseToken()).build(),
                new ConsumeResponseListener() {
                    @Override
                    public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
                        Log.e(TAG, "onConsumeResponse code = " + billingResult.getResponseCode() + " ,  msg = " + billingResult.getDebugMessage() + " , purchaseToken = " + purchaseToken);              // 消费成功  处理自己的流程,我选择先存入数据库
                        if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                            PurchaseHistoryBean purchaseHistory = new PurchaseHistoryBean();
                            purchaseHistory.uid = NumberParserUtil.parseLong(UserInfoManager.create().getUserId(), -1);
                            purchaseHistory.orderId = purchase.getOrderId();
                            purchaseHistory.purchaseToken = purchase.getPurchaseToken();
                            purchaseHistory.developerPayload = purchase.getDeveloperPayload();
                            purchaseHistory.productId = purchase.getSku();
                            purchaseHistory.purchaseTime = purchase.getPurchaseTime();
                            savePurchaseHistory(purchaseHistory, needToast);
                        } else {
                            // 消费失败,后面查询消费记录后再次消费,否则,就只能等待退款
                        }
                    }
                });

8.为了保证消费成功之后一定能通知到服务器,我自己处理了一下,先存数据库:

/**
 * 保存数据到数据库(已消费的数据)
 *
 * @param purchaseHistory 购买记录
 */
private void savePurchaseHistory(final PurchaseHistoryBean purchaseHistory, final boolean needToast) {
    PurchaseHistoryResponstory.insert(purchaseHistory, new DBExecuteCallback() {
        @Override
        public void onSuccess() {
            reportServer(purchaseHistory, needToast);
        }

        @Override
        public void onError() {
            reportServer(purchaseHistory, needToast);
        }
    });
}

9.最后一步,通知服务器,我已经支付成功了,把orderId,productId,purchaseToken等信息上报给服务器。

:前面mBillingClient. d的操作都建立在连接成功的情况下。但是这几步存在异常的情况,比如说支付成功了,但是没有消费成功(consumeAsync),消费成功了,但是上报服务器失败了,所以需要一些机制保证最后一定能上报给服务器。

三.解决问题

1.支付成功了,但是没有消费成功(consumeAsync),可以在某一个时机查询以前的账号发起的订单信息

/**
 * 查询最近的购买交易
 * 使用 Google Play 商店应用的缓存,而不发起网络请求
 * 建议在应用启动时和 onResume() 方法中调用 至少调用两次
 */
private void queryPurchase() {
    if (!isClientInit()) {
        return;
    }
    Purchase.PurchasesResult purchasesResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP);
    Log.e(TAG, "queryPurchase code = " + purchasesResult.getResponseCode() + " getPurchasesList = " + purchasesResult.getPurchasesList());
    // 查询成功且列表不为空
    if (purchasesResult.getResponseCode() == BillingClient.BillingResponseCode.OK && !purchasesResult.getPurchasesList().isEmpty()) {
        for (Purchase purchase : purchasesResult.getPurchasesList()) {
            handlePurchase(purchase, false);
        }
    }
}
执行成功之后再次处理消费流程handlePurchase(purchase, false);

2.消费成功了,但是通知服务器失败了,还记得之前存入数据库的操作吗savePurchaseHistory,这个时候派上用场了

/**
 * 查询列表,上传服务器
 */
private void queryPurchaseHistory() {
    PurchaseHistoryResponstory.queryList(new DefaultDBResultCallback<PurchaseHistoryBean>() {
        @Override
        public void onSuccess(List<PurchaseHistoryBean> purchaseHistoryBeans) {
            super.onSuccess(purchaseHistoryBeans);
            for (PurchaseHistoryBean purchaseHistory : purchaseHistoryBeans) {
                //上传自己的服务器
                reportServer(purchaseHistory, false);
            }
        }
    });
}

四.整体流程

五.填坑之路

##完成以上操作,正常情况下可以完成支付操作。但这只是正常情况,毕竟我们是在国内的环境,很多坑需要去填

1.应用内无法查询商品id,无法吊起支付窗口:

一定要等你的应用为**Published**状态之后,在app里面才能查到商品id,执行支付等操作,否则怎么样都查不到

2.应用已经发布了,但是还是吊不起支付窗口:

首先app需要安装google三件套,不知道怎么安装的,可以安装一个YouTube,进入app后会自动提示你需要安装google play,需要vpn,然后一定注意了,需要在权限设置里面,把google play的##允许应用在后台弹窗界面##这个权限打开,一定记得要打开

3.当一切准备就绪之后,报:目前还无法在您所在的国家/地区购买Google Play中的内容。这个因为在中国不允许。解决办法:

网页登录你的google账户:在设置里面,把你的地址改成美国或其他支持的国家,然后清除app内google play的数据,重新进入,重新选择地区(刚才你修改的地区),选完之后会提示你切换到美国的商店,然后再添加付款信息(中国的卡就行,我用的是招商银行的信用卡),这样就万事大吉了,之后就可以正常支付了。

六.测试支付,无需真正付款

整体步骤如下:
1.发布alpha/beta版本,保证应用是已发布状态
2.在alpha/beta版本添加测试人员,并勾选保存
3.把链接发给测试人员,让其点击链接加入测试
4.在账户详细信息里面,添加许可测试的邮箱账号,许可测试响应改为 “RESPOND_NORMALLY/LICENSED”,点击保存,需要一两分钟生效

:测试支付时遇到一个特别奇葩的问题,刚开始一两次支付显示的是“测试支付,无需付款”,后面再次支付居然要求用信用卡支付。然后,我在“许可测试” 这里,RESPOND_NORMALLY/LICENSED,切换一下就又好了(有时候需要支付时点击一下“税费另计”才会显示是测试支付),以此反复。 这里还没有想明白是那个环节出了问题。

总结

来来回回折腾了几天时间,主要是填写google play上的信息,审核,以及填坑占大部分,接入还是比较简单的,这里主要是做记录,方便以后查看。

推荐阅读