点关注不迷路,持续输出Unity干货文章。
嗨,大家好,我是新发。最近实在太忙了,博客停了好几天没更新。
项目要出海,需要接入Google
支付,今天就来说说如何接入Google
支付吧。
要接入
Google Console
上注册一个账号并申请一个应用,
Google Console
网址:https://developer.android.com/distribute/console
账号注册和应用申请不是本文重点,这里就不展开讲了,另:需要科学上网才能访问Google Console
。
Google
支付官方文档:https://developer.android.com/google/play/billing/integrate#java
Github
工程地址:https://github.com/android/play-billing-samples
Demo
下载下来后,使用Android Studio
打开ClassyTaxiJava
工程即可。
其中,BillingClientLifecycle.java
就是最主要的演示脚本。
Google
支付的流程略微有点复杂,为了方便大家理解,我把Google
支付的流程图画一下,图片可以放大看。
容易漏掉的就是补单。
国内硬核渠道的SDK
(比如应用宝、OPPO
、VIVO
、小米、华为等),一般支付完成,是SDK
服务端通过callback_url
(一般是一个https
请求)的方式回调给游戏服务端,游戏服务端进行发货。
Google
支付不一样,它没有callback_url
,那游戏服务端怎么知道用户支付完成了呢?
需要游戏客户端在支付完成后主动动通知服务端发货,确认发货后客户端再关闭订单。
正因为是由客户端来通知服务端发货的,所以就有可能会掉单,比如客户端支付成功后,还没来得及通知服务端发货,客户端就异常退出了。
这个时候,就需要补单了。游戏客户端在完成登录游戏服务端后,需要主动调用Google
的订单查询接口,把漏掉的单子补发货,发完货后,客户端关闭订单。
private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
@Override
public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
// To be implemented in a later section.
}
};
private BillingClient billingClient = BillingClient.newBuilder(activity)
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build();
支付事件在PurchasesUpdatedListener
中监听,比如支付完成:
@Override
public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
int responseCode = billingResult.getResponseCode();
String debugMsg = billingResult.getDebugMessage();
Log.d("GooglePay", "responseCode: $responseCode, debugMsg: $debugMsg");
if(null != purchases) {
for(Purchase purchase : purchases) {
if(BillingResponseCode.OK == responseCode) {
// TODO 通知服务端发货,发货成功后,把订单关闭
// handlePurchase(purchase); // 注意,必须确保服务器发货成功后再执行handlePurchase
}
}
}
}
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingResponseCode.OK) {
// The BillingClient is ready. You can query purchases here.
}
}
@Override
public void onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
});
判断是否已连接
if(billingClient.isReady())
{
}
List<String> skuList = new ArrayList<> ();
skuList.add("sku_id");
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(SkuType.INAPP);
billingClient.querySkuDetailsAsync(params.build(),
new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(BillingResult billingResult,
List<SkuDetails> skuDetailsList) {
// Process the result.
}
});
建议把查询结果做缓存,查过的商品,下次直接从缓存中获取即可,例:
private Map<String, SkuDetails> skuDetailsMap = new HashMap();
// ...
if(skuDetailsMap.containsKey("sku_id"))
{
// skuDetailsMap.get("sku_id");
return;
}
List<String> skuList = new ArrayList<> ();
skuList.add("sku_id");
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(SkuType.INAPP);
billingClient.querySkuDetailsAsync(params.build(),
new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(BillingResult billingResult,
List<SkuDetails> skuDetailsList) {
// Process the result.
int resultCode = billingResult.getResponseCode();
if(BillingResponseCode.Ok == resultCode) {
for(SkuDetails skuDetails : skuDetailsList) {
// 缓存
if(!skuDetailsMap.containsKey(skuDetails.getSku())) {
skuDetailsMap.put(skuDetails.getSku(), skuDetails);
}
}
}
}
});
// An activity reference from which the billing flow will be launched.
Activity activity = ...;
// Retrieve a value for "skuDetails" by calling querySkuDetailsAsync().
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.setObfuscatedAccountId(orderId) // 塞入订单号
.build();
int responseCode = billingClient.launchBillingFlow(activity, billingFlowParams).getResponseCode();
// Handle the result.
支付成功,服务端发货完成后,需要客户端将订单关闭。
void handlePurchase(Purchase purchase) {
// Purchase retrieved from BillingClient#queryPurchases or your PurchasesUpdatedListener.
Purchase purchase = ...;
// Verify the purchase.
// Ensure entitlement was not already granted for this purchaseToken.
// Grant entitlement to the user.
ConsumeParams consumeParams =
ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
ConsumeResponseListener listener = new ConsumeResponseListener() {
@Override
public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
if (billingResult.getResponseCode() == BillingResponseCode.OK) {
// Handle the success of the consume operation.
}
}
};
billingClient.consumeAsync(consumeParams, listener);
}
用户登录进游戏服务端后,需要执行一下查询订单,发现有掉单,需要通知服务端补发货,发货完成后,客户端关闭订单。
Purchase.PurchasesResult result = billingClient.queryPurchases(SkuType.INAPP);
if(BillingResponseCode.OK == result.getResponseCode()) {
for(Purchase purchase : result.getPurchasesList()) {
if(Purchase.PurchaseState.PURCHASED == purchase.getPurchaseState()) {
// TODO 通知服务端补发货,发货完成后,客户端关闭订单。
}
}
}
如果你是Android Studio
做的原生应用,那么直接在build.gradle
中配置一下即可。
dependencies {
// ...
// Google Play Billing Library.
implementation 'com.android.billingclient:billing:3.0.0'
// ...
}
如下:
如果是Unity
项目,则需要把依赖的jar
文件拷贝到Assets/Plugins/Android/libs
文件夹中。
我们可以通过Android Studio
来定位这个jar
文件,把鼠标移动到BillingClient
类上,按住Ctrl
键不放,点击,即可跳转到.class
文件里,即可通过.class
文件定位到.jar
文件所在的目录。
如下:
我们把classes.jar
文件重名名为google_billing_3.0.0.jar
,然后再丢进Unity
工程中即可。
完毕。
喜欢Unity
的同学,不要忘记点击关注,如果有什么Unity
相关的技术难题,也欢迎留言或私信~