android google 内购支付最新版本 6.0结算库 接入教程
2023/7/1 9:00:00 【次浏览】 本站
前言
各位同学 大家好有段时间没有个大家更新文章 ,最近在更新google的最新结算库 。所以就在这里分享给废话不多说。
官方文档地址
需要的依赖
def billing_version = "6.0.0" implementation "com.android.billingclient:billing:$billing_version"
请添加到build.gralde
效果图 :
具体接入
支付初始化
private BillingClient billingClient; billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) .enablePendingPurchases() .build(); if(billingClient!=null){ billingClient.startConnection(new BillingClientStateListener() { @Override public void onBillingSetupFinished(BillingResult billingResult) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { } } @Override public void onBillingServiceDisconnected() { } }); }
连接Google查询商品ID 信息
String productId ="xxxxx"; //请替换成自己的商品id List<QueryProductDetailsParams.Product> productList= new ArrayList<>(); productList.add(QueryProductDetailsParams.Product.newBuilder() .setProductId(productId) .setProductType(BillingClient.ProductType.INAPP) .build()); QueryProductDetailsParams queryProductDetailsParams = QueryProductDetailsParams.newBuilder(). setProductList(productList) .build(); if(billingClient!=null){ billingClient.queryProductDetailsAsync( queryProductDetailsParams, new ProductDetailsResponseListener() { public void onProductDetailsResponse(BillingResult billingResult, List<ProductDetails> productDetailsList) { } } ); }
调起支付界面
ProductDetails productDetails=productDetailsList.get(0); List<BillingFlowParams.ProductDetailsParams> productDetailsParamsList= new ArrayList<>(); productDetailsParamsList.add(BillingFlowParams.ProductDetailsParams.newBuilder() .setProductDetails(productDetails) .build()); BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build(); billingClient.launchBillingFlow((Activity) context, billingFlowParams);
支付回调
private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener(){ @Override public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) { for (Purchase purchase : purchases) { handlePurchase(purchase); Log.e(TAG, "getPurchaseToken: "+ purchase.getPurchaseToken() ); Log.e(TAG, "getSignature: "+ purchase.getSignature() ); Log.e(TAG, "getSignature: "+ purchase.getSignature() ); } } else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) { } else { } } };
我们拿到回调里面的 getPurchaseToken getSignature getSignature 信息之后可以去自己服务端进行验签 如果验签成功了才算是真正的成功支付成功 然后再进行消耗
商品消耗
private void handlePurchase(final Purchase purchase) { ConsumeParams consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build(); ConsumeResponseListener listener = new ConsumeResponseListener() { @Override public void onConsumeResponse(BillingResult billingResult, String purchaseToken) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { Log.e(TAG, "getPurchaseToken: "+ purchase.getPurchaseToken() ); Log.e(TAG, "getSignature: "+ purchase.getSignature() ); Log.e(TAG, "getSignature: "+ purchase.getSignature() ); } } }; if(billingClient!=null){ billingClient.consumeAsync(consumeParams, listener); } }
支付完成后下次支付前查询消耗
private void queryPurchasesAsync(){ if(billingClient!=null){ if(!billingClient.isReady()){ Toast.makeText(context,"BillingClient is not ready",Toast.LENGTH_SHORT).show(); } billingClient.queryPurchasesAsync( QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.INAPP).build(), new PurchasesResponseListener() { public void onQueryPurchasesResponse( BillingResult billingResult, List<Purchase> purchases) { if(billingResult.getResponseCode()==BillingClient.BillingResponseCode.OK){ if(purchases!=null&&purchases.size()>0){ for (Purchase purchase:purchases){ handlePurchase(purchase); } } } } } ); } }
请再 onResume 声明周期方法里面调用
@Override protected void onResume() { super.onResume(); queryPurchasesAsync(); }
完整接入示例
package com.example.myapplication;import androidx.annotation.NonNull;import androidx.appcompat.app.AppCompatActivity;import android.annotation.SuppressLint;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Toast;import com.android.billingclient.api.BillingClient;import com.android.billingclient.api.BillingClientStateListener;import com.android.billingclient.api.BillingFlowParams;import com.android.billingclient.api.BillingResult;import com.android.billingclient.api.ConsumeParams;import com.android.billingclient.api.ConsumeResponseListener;import com.android.billingclient.api.ProductDetails;import com.android.billingclient.api.ProductDetailsResponseListener;import com.android.billingclient.api.Purchase;import com.android.billingclient.api.PurchasesResponseListener;import com.android.billingclient.api.PurchasesUpdatedListener;import com.android.billingclient.api.QueryProductDetailsParams;import com.android.billingclient.api.QueryPurchasesParams;import com.testgame.demo.R;import java.util.ArrayList;import java.util.List;/** * 创建人:xuqing * 创建时间:2023年5月18日14:53:03 * 类说明:google支付测试 * * */public class MainActivity extends AppCompatActivity { private static final String TAG = "-----MainActivity-----"; private Context context=MainActivity.this; private BillingClient billingClient; private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() { @Override public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) { for (Purchase purchase : purchases) { handlePurchase(purchase); Log.e(TAG, "getPurchaseToken: "+ purchase.getPurchaseToken() ); Log.e(TAG, "getSignature: "+ purchase.getSignature() ); Log.e(TAG, "getSignature: "+ purchase.getSignature() ); } } else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) { } else { } } }; private void handlePurchase(final Purchase purchase) { ConsumeParams consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build(); ConsumeResponseListener listener = new ConsumeResponseListener() { @Override public void onConsumeResponse(BillingResult billingResult, String purchaseToken) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { Log.e(TAG, "getPurchaseToken: "+ purchase.getPurchaseToken() ); Log.e(TAG, "getSignature: "+ purchase.getSignature() ); Log.e(TAG, "getSignature: "+ purchase.getSignature() ); } } }; if(billingClient!=null){ billingClient.consumeAsync(consumeParams, listener); } } @SuppressLint("MissingInflatedId") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initgooglePlay(); findViewById(R.id.togooglepaybtn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { toGooglePay(); } }); } private void initgooglePlay() { billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) .enablePendingPurchases() .build(); if(billingClient!=null){ billingClient.startConnection(new BillingClientStateListener() { @Override public void onBillingSetupFinished(BillingResult billingResult) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { } } @Override public void onBillingServiceDisconnected() { } }); } } private void toGooglePay(){ String productId ="xxxx"; List<QueryProductDetailsParams.Product> productList= new ArrayList<>(); productList.add(QueryProductDetailsParams.Product.newBuilder() .setProductId(productId) .setProductType(BillingClient.ProductType.INAPP) .build()); QueryProductDetailsParams queryProductDetailsParams = QueryProductDetailsParams.newBuilder(). setProductList(productList) .build(); if(billingClient!=null){ billingClient.queryProductDetailsAsync( queryProductDetailsParams, new ProductDetailsResponseListener() { public void onProductDetailsResponse(BillingResult billingResult, List<ProductDetails> productDetailsList) { if(productDetailsList!=null&&productDetailsList.size()>0){ ProductDetails productDetails=productDetailsList.get(0); List<BillingFlowParams.ProductDetailsParams> productDetailsParamsList= new ArrayList<>(); productDetailsParamsList.add(BillingFlowParams.ProductDetailsParams.newBuilder() .setProductDetails(productDetails) .build()); BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build(); billingClient.launchBillingFlow((Activity) context, billingFlowParams); }else { Toast.makeText(context,"商品ID无效",Toast.LENGTH_SHORT).show(); } } } ); } } private void queryPurchasesAsync(){ if(billingClient!=null){ if(billingClient.isReady()){ Toast.makeText(context,"BillingClient is not ready",Toast.LENGTH_SHORT).show(); } billingClient.queryPurchasesAsync( QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.INAPP).build(), new PurchasesResponseListener() { public void onQueryPurchasesResponse( BillingResult billingResult, List<Purchase> purchases) { if(billingResult.getResponseCode()==BillingClient.BillingResponseCode.OK){ if(purchases!=null&&purchases.size()>0){ for (Purchase purchase:purchases){ handlePurchase(purchase); } } } } } ); } } @Override protected void onResume() { super.onResume(); queryPurchasesAsync(); } @Override public void onStop() { super.onStop(); } @Override protected void onPause() { super.onPause(); }}
需要注意的点
我们的google 支付初始化不要多次初始化 不然会出现多次回调的 会影响到我们支付回调里面进行数据上报的逻辑 。支付消耗查询也可以放在每次支付之前先查询后再去进行下一笔支付 ,还有示例中部分底和官方写法不一样是我改过的 ImmutableList.of 这个其实Java里面的 声明一个非空集合 因为我这边一直导入不了 所以就改掉了 其余代码跟官方一毛一样
支付调不起来的几个原因
1 保证拿到商品ID 是正确的可以在google play后台查看到
2 保证手机里面 Google账号是可以支付的
3、安装的app包的versionName、versionCode 和 Google Play Console上传的不一样
Google Play Console - 所有应用 - 查看应用 (上传安装的app或者修改版本号)
4、安装的app包的签名和上传到Google Play Console的包签名不一致
Google Play Console - 所有应用 - 查看应用 -设置 - 应用完整性 (查看签名是否一致)
5 保证vpn 翻墙工具稳定
最后总结:
如果你是4.0.0版本的结算库 请服务查看 从 Google Play 结算库版本 4 或 5 迁移到版本 6 说明里面有些api 还是有改动 最好用最新方法 不要用过时的方法 如果你是第一次接入就按照次文档或者官方最新文档接入即可
手机扫码查看当前文章: