海外登录支付调研记录

  • Post author:
  • Post category:其他

一、前期调研准备

1、google play商店配置

在360手机助手下载“GO谷歌安装器”,不要在手机助手上直接下载Google play,不知道为啥不能用。建议使用“GO谷歌安装器”里面配置环境的时候会配置安装Google play

2、facebook下载安装

facebook在Google play上找不到。地址一上传就审核拒绝,大家自己找APKPure,里面有这个应用

3、关于google play支付

前期准备
(1)申请一个google play开发者账号,需要支付25美金,确保你使用的是visa卡,不然支付费用的时候会有问题。
(2)提前准备好一个apk(占位用,只需要放入结算权限,不需要接入google 结算sdk),在google play控制台上传你的apk
(3)发布一个beta的测试版本(注意第一次在Google play上发布应用的时候审核时间会比较慢,而且提交的内容要接近真实游戏,不要自己编造,我提交的apk相关的内容都是自己的测试demo,然后审核就被拒了两次,建议提交内容的时候规范真实点,比较容易好过,只需要提交测试版,个人觉得正式版的审核会更慢),发布之前需要按照后台提示完成以下选项(提交商品详情内容)(确定内容分级)(选择发布范围)等,之后才能正常发布
(4)添加测试人员,等应用审核通过之后,会得到一个地址,把地址发给对方,让对方点击同意加入测试即可
(5)需要创建应用内商品(商品id,商品描述,定价),按提示填就可以了
(6)注意注意注意,如果要测试一定要审核通过才行啊!!!!!
(7)添加无需真实支付的测试人员:链接地址

目前遇到的问题是,只有两种账号能支付成功(测试账号+付费区、测试账号+visa卡支付过的):
==即使添加了测试账号,你的账号如果是非付费区,依然会连接支付服务失败。==这里建议大家进行下修改地区,只需要在google账号设置里增加地址就行,至于具体的地址,在网上都能搜到。

二、facebook

1、facebook环境配置

注意点
(1):按照文档提示步骤添加配置文件,facebook_app_id和fb_login_protocol_scheme就在配置的string.xml文件中
(2):重要~ 发布密钥散列。

keytool -exportcert -alias basefunctool_release -keystore "keystore文件" | openssl-0.9.8e_X64\bin\openssl sha1 -binary | openssl-0.9.8e_X64\bin\openssl base64

opnssl下载地址:https://download.csdn.net/download/fanwei4751/12613256

facebook登录后报错:Key hash does not match。明明是按照官方的提示设置的。最后才发现问题便出在openssl上,openssl较新的版本09.8k存在bug,其计算得出的key hash可能是错误的,我们回滚到0.9.8e版本,问题就解决了。

2、报错
SERVER_ERROR: [code] 1675030 [message]: 执行查询时出错。 [extra]: 

账号权限不足,需要在facebook后台添加测试账号。一般在上线前调试阶段会用到

三、Google 结算接入

1、确保Google Play配置正确

(1)在Google Play Console上传测试版本APK,并发布测试版本成功,确定上传APK的包名、版本号、APK签名。
(2)在Google Play Console上配置应用内商品
(3)将测试账号加入测试计划
(4)确保本地的测试包与上传的测试版本APK的包名、版本号、APK签名相同

2、消耗型商品支付接入

(1)连接到 Google Play和注册支付监听

调用支付前需要先保证初始化成功。如果初始化失败,建议重试几次。isConnectSucc = true就表示初始化成功了,可以进行后续操作了

private BillingClient billingClient;
private boolean isConnectSucc = false; //google支付是否连接上成功

/**
 * 初始化支付 :连接到 Google Play
 */
private void connectPay() {
    //purchasesUpdatedListener是支付后的回调监听
    billingClient = BillingClient.newBuilder(this).enablePendingPurchases().setListener(purchasesUpdatedListener).build();

    billingClient.startConnection(new BillingClientStateListener() {
        @Override
        public void onBillingSetupFinished(BillingResult billingResult) {
            if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                isConnectSucc = true;
                // The BillingClient is ready. You can query purchases here.
                showLog("Init success,The BillingClient is ready");
                //每次进行重连的时候都应该消耗之前缓存的商品,不然可能会导致用户支付不了
                queryAndConsumePurchase();
            }
        }

        @Override
        public void onBillingServiceDisconnected() {
            //断开连接,当收到此回调时可以重新连接google否则会出现服务无法使用问题
            showLog("Init failed,Billing Service Disconnected,The BillingClient is not ready");
        }
    });
}
(2)查询商品信息后调用支付。支付的结果会显示在初始化时注册的支付监听中
1) 先查询商品信息
private List<SkuDetails> mSkuDetailsList = new ArrayList<>();//商品信息
/**
 * 查询商品信息
 */
private void queryDetail(String goodId) {
    if (TextUtils.isEmpty(goodId)) {
        //商品id不能为空
        return;
    }
    //清除当前商品信息,开始重置
    mSkuDetailsList.clear();

    //查询商品信息
    List<String> skuList = new ArrayList<>();
    skuList.add(goodId);
    SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
    params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
    billingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() {
        @Override
        public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) {
            showLog("querySkuDetailsAsync Code:" + billingResult.getResponseCode()
                    + ",size:" + skuDetailsList.size());

            if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                if (skuDetailsList != null && skuDetailsList.size() > 0) {
                    showLog("skuDetailsList is success.");
                    //查询商品成功
                    mSkuDetailsList.addAll(skuDetailsList);
                } else {
                    showLog("skuDetailsList is empty.");
                }
            } else {
                showLog("Get SkuDetails Failed,Msg=" + billingResult.getDebugMessage());
            }
        }
    });
}

2)查询到商品信息,去支付
/**
 * 查询商品详情列表后去支付
 * <p>
 * 请从界面线程调用(必须在UI线程调用)
 *
 * @param skuDetailsList
 */
public void startInappPay(List<SkuDetails> skuDetailsList) {
    showLog("startInappPay start ");
    for (SkuDetails skuDetails : skuDetailsList) {
        String sku = skuDetails.getSku();
        //折扣价
        String price = skuDetails.getPrice();
        //原价
        String originalPrice = skuDetails.getOriginalPrice();
        //货币标识
        String currency = skuDetails.getPriceCurrencyCode();
        //...其他详细信息,打印SkuDetails就可以看到

        //调起支付
        BillingFlowParams flowParams = BillingFlowParams.newBuilder().setSkuDetails(skuDetails).build();
        BillingResult billingResult = billingClient.launchBillingFlow(this, flowParams);
        if (billingResult != null) {
            int responseCode = billingResult.getResponseCode();
            if (responseCode == BillingClient.BillingResponseCode.OK) {
                showLog("成功启动google支付");
            } else {
                showLog("LaunchBillingFlow Fail,code=" + responseCode);
            }
        }
    }
}
3)处理支付的监听,在初始化的时候需要传入
private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
   @Override
    public void onPurchasesUpdated(BillingResult billingResult, @Nullable List<Purchase> purchases) {
        //支付后的回调在这里,当支付状态改变时调用,ok为支付成功,否则为支付失败
        if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
            showLog("Purchase success 支付成功,开始后续处理");
            //支付成功,开始进行后续处理
            if (purchases != null && purchases.size() > 0) {
                for (Purchase purchase : purchases) {
                    handlePurchase(purchase);
                }
            } else {
                showLog("Purchase success but empty!!!!");
            }
        } else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) {
            //用户取消
            showLog("Purchase cancel");
        } else {
            //支付错误
            showLog("Pay result error,code=" + billingResult.getResponseCode() + "\nerrorMsg=" + billingResult.getDebugMessage());
        }
    }
};
(3)支付完成后消耗商品
/**
 * 消费商品
 * 支付成功后一定要消费商品,如果不消费商品三天后会退回到用户账号中
 *
 * @param purchase
 */
private void consumePuchase(final Purchase purchase) {
    showLog("consumePuchase start ");
    ConsumeParams.Builder consumeParams = ConsumeParams.newBuilder();
    consumeParams.setPurchaseToken(purchase.getPurchaseToken());
    consumeParams.setDeveloperPayload(purchase.getDeveloperPayload());
    billingClient.consumeAsync(consumeParams.build(), new ConsumeResponseListener() {
        @Override
        public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
            showLog("onConsumeResponse, code=" + billingResult.getResponseCode());
            if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                showLog("onConsumeResponse success");
                //TODO :消费成功,游戏进行发放商品
                //TODO :这里如果支付成功并且消费成功了,游戏没有发货成功的话只能联系游戏客服针对订单去处理发货
            } else {
                // 消费失败,后面查询消费记录后再次消费,否则,就只能等待退款
                showLog("onConsumeResponse getDebugMessage==" + billingResult.getDebugMessage());
                if (billingResult.getDebugMessage().contains("Server error, please try again")) {
                    showLog("onConsumeResponse err");
                    queryAndConsumePurchase();
                }
            }
        }
    });
}
(4)查询最近的购买交易,每次连接成功的时候要进行查询,发现有需要消费的商品需要再次消费,保证支付正常。还需要注意的是还有另外一种查询方式(queryPurchaseHistoryAsync() ),但是会发起网络请求,可能会向用户收费,因此我选择下面这种不会向用户收费的方法。
/**
 * 查询最近的购买交易,并消耗商品
 */
private void queryAndConsumePurchase() {
    showLog("queryAndConsumePurchase start");
    //queryPurchases() 方法会使用 Google Play 商店应用的缓存,而不会发起网络请求
    billingClient.queryPurchaseHistoryAsync(BillingClient.SkuType.INAPP, new PurchaseHistoryResponseListener() {
        @Override
        public void onPurchaseHistoryResponse(BillingResult billingResult, List<PurchaseHistoryRecord> purchaseHistoryRecordList) {
            if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK
                    && purchaseHistoryRecordList != null && !purchaseHistoryRecordList.isEmpty()) {
                showLog("有购买交易记录");
                for (PurchaseHistoryRecord purchaseHistoryRecord : purchaseHistoryRecordList) {
                    // Process the result.
                    //确认购买交易,不然三天后会退款给用户
                    try {
                        Purchase purchase = new Purchase(purchaseHistoryRecord.getOriginalJson(), purchaseHistoryRecord.getSignature());
                        handlePurchase(purchase);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            } else {
                showLog("没有查询到历史交易记录");
            }
        }
    });
}
(5)其他
/***
 * 支付完成,消费商品成功后,游戏进行商品发放
 * 如要增加服务端校验,请参照(在服务器上验证购买交易)
 *  https://
 * developer.android.google.cn/google/play/billing/billing_library_overview?hl=zh-cn#java
 * @param purchase
 */
public void handlePurchase(Purchase purchase) {
    showLog("handlePurchase start");
    if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
        showLog("Purchase purchased");
        //消耗商品。确认购买交易,不然三天后会退给用户
        consumePuchase(purchase);
        //TODO:这里可以添加订单找回功能,防止变态用户付完钱就杀死App的这种
    } else if (purchase.getPurchaseState() == Purchase.PurchaseState.PENDING) {
        //需要用户确认,待处理交易
        showLog("Purchase pending,need to check");
        //TODO :待处理交易,在这里,您可以向用户确认他们已经开始了待定的购买,并且要完成它,他们应该遵循给他们的指示。您还可以选择提醒用户在将来完成购买,如果您检测到它仍在等待。
    }
}

3、错误码

错误码 描述
-3 BILLING_RESPONSE_RESULT_SERVICE_TIMEOUT
-2 BILLING_RESPONSE_RESULT_FEATURE_NOT_SUPPORTED
-1 BILLING_RESPONSE_RESULT_SERVICE_DISCONNECTED
0 BILLING_RESPONSE_RESULT_OK 成功
1 BILLING_RESPONSE_RESULT_USER_CANCELED 用户按上一步或取消对话框
2 BILLING_RESPONSE_RESULT_SERVICE_UNAVAILABLE 网络连接断开
3 BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE 所请求的类型不支持Google Play结算服务AIDL版本
4 BILLING_RESPONSE_RESULT_ITEM_UNAVAILABLE 请求的商品已不再出售
5 BILLING_RESPONSE_RESULT_DEVELOPER_ERROR 提供给 API 的参数无效。此错误也可能说明应用未针对 Google Play 结算服务正确签名或设置,或者在其清单中缺少必要的权限。
6 BILLING_RESPONSE_RESULT_ERROR API 操作期间出现严重错误
7 BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED 未能购买,因为已经拥有此商品
8 BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED 未能消费,因为尚未拥有此商品

4、支付可能失败的原因

(1)确认在Google Play配置是否正确?并且确认应用已经审核通过,否则不能使用该功能
(2)手机上安装的测试apk与Google Play Console上传的apk配置是否相同?包名、签名、版本号是否相同?
(3)手机上登录的Google Play帐号是否处于付费区域内,查看Google Play里是否有付费应用?
(4)手机上登录的Google Play帐号是否加入了测试计划?
(5)清理Google Play Store缓存重试


版权声明:本文为fanwei4751原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。