一、前期调研准备
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缓存重试