zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

教你接入Google谷歌支付V3版本,图文讲解(Android、Unity)

AndroidGoogle谷歌 版本 Unity 讲解 图文 支付
2023-09-11 14:19:34 时间

转自:https://blog.csdn.net/linxinfa/article/details/115916000

一、前言

项目要出海,需要接入Google支付,今天就来说说如何接入Google支付吧。

要接入Google支付,需要先在Google Console上注册一个账号并申请一个应用,
Google Console网址:https://developer.android.com/distribute/console
账号注册和应用申请不是本文重点,这里就不展开讲了,另:需要科学的上网才能访问Google Console。

二、Google支付官方文档

Google支付官方文档:https://developer.android.com/google/play/billing/integrate#java

三、Google支付Github Demo工程

Github工程地址:https://github.com/android/play-billing-samples

Demo下载下来后,使用Android Studio打开ClassyTaxiJava工程即可。

其中,BillingClientLifecycle.java就是最主要的演示脚本。

四、Google支付流程图

Google支付的流程略微有点复杂,为了方便大家理解,我把Google支付的流程图画一下,图片可以放大看。

容易漏掉的就是补单。
国内硬核渠道的SDK(比如应用宝、OPPO、VIVO、小米、华为等),一般支付完成,是SDK服务端通过callback_url(一般是一个https请求)的方式回调给游戏服务端,游戏服务端进行发货。
Google支付不一样,它没有callback_url,那游戏服务端怎么知道用户支付完成了呢?
需要游戏客户端在支付完成后主动动通知服务端发货,确认发货后客户端再关闭订单。
正因为是由客户端来通知服务端发货的,所以就有可能会掉单,比如客户端支付成功后,还没来得及通知服务端发货,客户端就异常退出了。
这个时候,就需要补单了。游戏客户端在完成登录游戏服务端后,需要主动调用Google的订单查询接口,把漏掉的单子补发货,发完货后,客户端关闭订单。

五、Google支付接口讲解

1、初始化(监听支付事件)

 1 private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
 2     @Override
 3     public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
 4         // To be implemented in a later section.
 5     }
 6 };
 7 
 8 private BillingClient billingClient = BillingClient.newBuilder(activity)
 9     .setListener(purchasesUpdatedListener)
10     .enablePendingPurchases()
11     .build();

支付事件在PurchasesUpdatedListener中监听,比如支付完成:

 1   @Override
 2     public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
 3         int responseCode = billingResult.getResponseCode();
 4         String debugMsg = billingResult.getDebugMessage();
 5         Log.d("GooglePay", "responseCode: $responseCode, debugMsg: $debugMsg");
 6         if(null != purchases) {
 7             for(Purchase purchase : purchases) {
 8                 if(BillingResponseCode.OK == responseCode) {
 9                     // TODO 通知服务端发货,发货成功后,把订单关闭
10                     // handlePurchase(purchase);   // 注意,必须确保服务器发货成功后再执行handlePurchase
11                 }
12             }
13         }
14     }

2、连接Google服务器(必须)

 1 billingClient.startConnection(new BillingClientStateListener() {
 2     @Override
 3     public void onBillingSetupFinished(BillingResult billingResult) {
 4         if (billingResult.getResponseCode() ==  BillingResponseCode.OK) {
 5             // The BillingClient is ready. You can query purchases here.
 6         }
 7     }
 8     @Override
 9     public void onBillingServiceDisconnected() {
10         // Try to restart the connection on the next request to
11         // Google Play by calling the startConnection() method.
12     }
13 });

判断是否已连接

1 if(billingClient.isReady())
2 {
3 }

3、查询商品信息(通过sku_id查询)

 1 List<String> skuList = new ArrayList<> ();
 2 skuList.add("sku_id");
 3 SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
 4 params.setSkusList(skuList).setType(SkuType.INAPP);
 5 billingClient.querySkuDetailsAsync(params.build(),
 6     new SkuDetailsResponseListener() {
 7         @Override
 8         public void onSkuDetailsResponse(BillingResult billingResult,
 9                 List<SkuDetails> skuDetailsList) {
10             // Process the result.
11         }
12     });

建议把查询结果做缓存,查过的商品,下次直接从缓存中获取即可,例:

 1 private Map<String, SkuDetails> skuDetailsMap = new HashMap();
 2 
 3 // ...
 4 if(skuDetailsMap.containsKey("sku_id"))
 5 {
 6     // skuDetailsMap.get("sku_id");
 7     return;
 8 }
 9 
10 List<String> skuList = new ArrayList<> ();
11 skuList.add("sku_id");
12 SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
13 params.setSkusList(skuList).setType(SkuType.INAPP);
14 billingClient.querySkuDetailsAsync(params.build(),
15     new SkuDetailsResponseListener() {
16         @Override
17         public void onSkuDetailsResponse(BillingResult billingResult,
18                 List<SkuDetails> skuDetailsList) {
19             // Process the result.
20             int resultCode = billingResult.getResponseCode();
21             if(BillingResponseCode.Ok == resultCode) {
22                 for(SkuDetails skuDetails : skuDetailsList) {
23                     // 缓存
24                     if(!skuDetailsMap.containsKey(skuDetails.getSku())) {
25                         skuDetailsMap.put(skuDetails.getSku(), skuDetails);
26                     }
27                 }
28                 
29             }
30         }
31     });

4、拉起支付页(需要传sku和订单号)

 1 // An activity reference from which the billing flow will be launched.
 2 Activity activity = ...;
 3 
 4 // Retrieve a value for "skuDetails" by calling querySkuDetailsAsync().
 5 BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
 6         .setSkuDetails(skuDetails)
 7         .setObfuscatedAccountId(orderId)   // 塞入订单号
 8         .build();
 9 int responseCode = billingClient.launchBillingFlow(activity, billingFlowParams).getResponseCode();
10 
11 // Handle the result.

5、关闭订单(发货完后执行)

支付成功,服务端发货完成后,需要客户端将订单关闭。

 1 void handlePurchase(Purchase purchase) {
 2     // Purchase retrieved from BillingClient#queryPurchases or your PurchasesUpdatedListener.
 3     Purchase purchase = ...;
 4 
 5     // Verify the purchase.
 6     // Ensure entitlement was not already granted for this purchaseToken.
 7     // Grant entitlement to the user.
 8 
 9     ConsumeParams consumeParams =
10         ConsumeParams.newBuilder()
11             .setPurchaseToken(purchase.getPurchaseToken())
12             .build();
13 
14     ConsumeResponseListener listener = new ConsumeResponseListener() {
15         @Override
16         public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
17             if (billingResult.getResponseCode() == BillingResponseCode.OK) {
18                 // Handle the success of the consume operation.
19             }
20         }
21     };
22 
23     billingClient.consumeAsync(consumeParams, listener);
24 }

6、查询订单(补单用)

用户登录进游戏服务端后,需要执行一下查询订单,发现有掉单,需要通知服务端补发货,发货完成后,客户端关闭订单。

1 Purchase.PurchasesResult result = billingClient.queryPurchases(SkuType.INAPP);
2 if(BillingResponseCode.OK == result.getResponseCode()) {
3     for(Purchase purchase : result.getPurchasesList()) {
4         if(Purchase.PurchaseState.PURCHASED == purchase.getPurchaseState()) {
5             // TODO 通知服务端补发货,发货完成后,客户端关闭订单。
6         }
7     }
8 }

六、Unity如何拿到billing sdk的jar文件

如果你是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工程中,
googlebilling其实是aar,是包含一些资源文件的,所以我们只拷贝jar还不够,jar文件外层的这些文件也需要。

不过这里建议使用下面这种方式一步到位下载aar文件。
进入googlemaven网站:https://mvnrepository.com/

直接搜索你要下载的库即可。
比如搜索com.android.billingclient:billing

直接下载aar文件。

七、补充

1、添加BILLING权限

提审Google Play,需要添加BILLING权限。
AndroidManifest.xml中添加这个:

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

2、billing v2版与v3版的区别
参见Google官方文档,这里:https://developer.android.com/google/play/billing/migrate

八、结束语
完毕。
喜欢Unity的同学,不要忘记点击关注,如果有什么Unity相关的技术难题,也欢迎留言或私信~