文章转载自:https://gitee.com/tjbaobao/GoogleBuillingUtil/blob/master/GoogleBillingUtil.java

README.md:

基于com.android.billingclient:billing:1.2,对整个支付流程进行封装。

最新版正在内测,有兴趣的朋友可以尝试使用最新版:GoogleBilling1.2.1

  • 1、将所有接口统一到OnGoogleBillingListener,从此只需要设置一个监听器就能选择性监听所有事件了。
  • 2、优化逻辑,条理更清晰,解决了旧版本带来的监听器设置与清除逻辑混乱的问题。
  • 3、添加在线订单查询方法,能够获取所有历史订单(但需要注意,获取的订单暂时无法判断其有效性)

QQ群交流:425219113(计算机语言交流)

=============使用方法==================

  • 下载GoogleBuillingUtil

  • API接入

  1. AndroidStudio
==========build.gradle(Module)==========android {dependencies {implementation 'com.android.billingclient:billing:1.2'//如果用到isGooglePlayServicesAvailable方法需要导入这个包,这个方法也可以去掉。implementation "com.google.android.gms:play-services-location:16.0.0"}
}
  1. Eclipse: 我的博客里面有提取的billing:1.0.jar可以下载使用。博客地址见最下面的版本描述。
  • 设置支付权限
//aar里面自带权限了,app可以不理会,但其他集成方式需要确保有这个权限。
<uses-permissionandroid:name="com.android.vending.BILLING"android:required="false"/>
  • 商品Id配置(必须)
//在GoogleBillingUtil.build之前调用。只需要设置一次。
GoogleBillingUtil.setSkus(new String[]{"内购商品id"},new String[]{"订阅商品id"})//没有的时候传null或者new String[]{},而不是new String[]{""}
  • 代码示例
private GoogleBillingUtil googleBillingUtil = null;
private MyOnPurchaseFinishedListener mOnPurchaseFinishedListener = new MyOnPurchaseFinishedListener();//购买回调接口
private MyOnQueryFinishedListener mOnQueryFinishedListener = new MyOnQueryFinishedListener();//查询回调接口
private MyOnStartSetupFinishedListener mOnStartSetupFinishedListener = new MyOnStartSetupFinishedListener ();//启动结果回调接口
private MyOnConsumeResponseListener mOnConsumeResponseListener = new MyOnConsumeResponseListener();//消耗结果回调接口
  1. 创建示例,需要在build之前设置回调接口,接口可以选择性设置
@Override
protected void onCreate(...) {super.onCreate(...);googleBillingUtil = GoogleBillingUtil.getInstance().setOnPurchaseFinishedListener(mOnPurchaseFinishedListener)//注意,监听器设置是可选的,视个人需求设置。.setOnQueryFinishedListener(mOnQueryFinishedListener).setOnStartSetupFinishedListener(mOnStartSetupFinishedListener).setOnConsumeResponseListener(mOnConsumeResponseListener ).build(context);
}
  1. 发起内购或者订阅
public void queryInventoryInApp() 查询内购商品信息列表
public void queryInventorySubs() 查询订阅商品信息列表
public void purchaseInApp(Activity activity,String skuId) 发起内购
public void purchaseSubs(Activity activity,String skuId) 发起订阅
  1. 清除监听器。
//如果下个页面或者上个页面没有使用到googleBuillingUtil.getInstance(),那么就需要在finish或者startActivity之前调用cleanListener()方法,来清除接口。
//可以尝试这样
@Overridepublic void onBackPressed() {GoogleBillingUtil.cleanListener();super.onBackPressed();}
//返回键点击
public void onBackClick(){GoogleBillingUtil.cleanListener();this.finish();}//如果只使用一次googleBuillingUtil,可以选择使用endConnection()方法断开google服务的连接,下次使用重新连接。
  1. 接口说明
//查询商品信息回调接口
private class MyOnQueryFinishedListener implements GoogleBillingUtil.OnQueryFinishedListener
{@Overridepublic void onQuerySuccess(String skuType,List<SkuDetails> list) {//查询成功,返回商品列表,//skuDetails.getPrice()获得价格(文本)//skuDetails.getType()获得类型 sub或者inapp,因为sub和inapp的查询结果都走这里,所以需要判断。//googleBillingUtil.getSubsPositionBySku(skuDetails.getSku())获得当前subs sku的序号//googleBillingUtil.getInAppPositionBySku(skuDetails.getSku())获得当前inapp suk的序号}@Overridepublic void onQueryFail(int responseCode) {//查询失败}@Overridepublic void onQueryError() {//查询错误}
}
//服务初始化结果回调接口
private class MyOnStartSetupFinishedListener implements GoogleBillingUtil.OnStartSetupFinishedListener
{
//...;
}
//购买商品回调接口
private class MyOnPurchaseFinishedListener implements GoogleBillingUtil.OnPurchaseFinishedListener
{@Overridepublic void onPurchaseSuccess(List<Purchase> list) {//内购或者订阅成功,可以通过purchase.getSku()获取suk进而来判断是哪个商品}@Overridepublic void onPurchaseFail(int responseCode) {}@Overridepublic void onPurchError() {}
}

==================响应代码汇总(官方地址)=============

响应代码 说明
BILLING_RESPONSE_RESULT_OK 0 成功
BILLING_RESPONSE_RESULT_USER_CANCELED 1 用户按上一步或取消对话框
BILLING_RESPONSE_RESULT_SERVICE_UNAVAILABLE 2 网络连接断开
BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE 3 所请求的类型不支持 Billing API 版本(支付环境问题)
BILLING_RESPONSE_RESULT_ITEM_UNAVAILABLE 4 请求的商品已不再出售。
BILLING_RESPONSE_RESULT_DEVELOPER_ERROR 5 提供给 API 的参数无效。此错误也可能说明未在 Google Play 中针对应用内购买结算正确签署或设置应用,或者应用在其清单中不具备所需的权限。
BILLING_RESPONSE_RESULT_ERROR 6 API 操作期间出现严重错误
BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED 7 未能购买,因为已经拥有此商品
BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED 8 未能消费,因为尚未拥有此商品

==================常见问题=============

1. 初始化失败,错误码:3,这是支付环境问题。

有以下可能:用的是模拟器,三件套版本太旧,应用的支付环境没配置(接入谷歌服务,支付权限),vpn地域不支持。

解决方法:a.先验证环境。在商店下载一个有内购的应用,看能否进行内购。b.如果别人的能进行内购之后,再次测试你的应用,看是否正常,来确认应用的支付环境是否正常。

2. 能够查询价格,但无法购买,提示"商品无法购买"之类。

这是基础配置问题,有以下可能:版本号与线上版本不对应,不是测试账号(大概率),商品状态有问题不支持支付,现在有人反映签名也需要对应。

3. 能够查询价格,但无法调起支付都没有弹窗,错误码:3,报错:Error:In-app billing error: Null data in IAB activity resul。

原因是没有给Google play商店弹窗权限,国内很多手机都有弹窗权限管理,特别是小米,如果没允许,是不会有任何提示,并且拦截了的。(这个问题在新版的gp商店已经不存在)

4. 支付提示成功,但却走onQueryFail回调,并且返回的商品列表为null。

这是因为你调错了方法,记得purchaseInApp是内购的,purchaseSubs是订阅的。查询的时候同理。另外查询的时候报错,很有可能是你setSKUS的时候传了一个空字符串,而不是空数组。

  1. 内购对支付环境的要求很高,最好测试的时候找那些绑定了信用卡的账号来测试,多换几台手机来测,不然有可能什么都不提示,直接失败。另外就是翻墙,应用的包名、版本号需要对应,商品id不要有错。

  2. 查询已购买的商品列表时,googleplay返回的是其本地缓存的内容,具体什么时候会联网更新,还有更新频率,这个不是很清楚,反正知道不是实时的就行,不会很影响使用。例如订阅,如果说是12:00:00就到期了,但你12:10:00上去或者还能查到记录,但再过一会肯定恢复正常。

  3. 万能的测试方法: a. 确认环境正常:下载一个需要内购的app进行测试,环境不正常则更新三件套,或者找一台正常真机来测。 b.确认商品正常:找一个走通了购买流程的项目,将自己的信息替换上去,看是否正常。不正常则看是否已经是测试账号登录了,商品是否处于能够支付的状态。 c.确认代码正常: 找一个能够购买的项目,将这个项目的信息替换上去,看是否正常。代码问题的概率比较小,因为支付只要包名和版本号对应就行了,当然,接入谷歌服务和设置支付权限也是必须的。 d.还有问题,加群反馈看看?

==================API说明=============

//初始化
1、public static GoogleBillingUtil getInstance() 获取单实例
2、public GoogleBillingUtil build() 创建内购实例,连接谷歌支付服务(如果未创建、未连接),并查询商品信息列表。如果默认自动消耗已内购但未被消耗的商品,可以通过设置isAutoConsumeAsync改变。
3、public void startConnection() 连接谷歌支付服务(一般情况下不需要手动调用,build的时候已经调用了)//查询、购买与消耗
4、public void queryInventoryInApp() 查询内购商品信息列表
5、public void queryInventorySubs() 查询订阅商品信息列表
6、public void purchaseInApp(Activity activity,String skuId) 发起内购
7、public void purchaseSubs(Activity activity,String skuId) 发起订阅
8、public void consumeAsync(String purchaseToken) 消耗商品(一般情况下不需要手动调用,内购的时候自动调用了)//购买历史、有效订阅数
9、public List<Purchase> queryPurchasesInApp() 获取已经内购的商品列表
10、public List<Purchase> queryPurchasesSubs() 获取已经订阅的商品列表
11、public int getPurchasesSizeSubs() 获取有效订阅的数量(-1查询失败,0没有有效订阅,>0具有有效的订阅)//便捷工具
12、public int getSubsPositionBySku(String sku) 通过sku获取订阅商品序号
13、public int getInAppPositionBySku(String sku) 通过sku获取内购商品序号
14、public String getSubsSkuByPosition(int position) 通过序号获取订阅sku
15、public String getInAppSkuByPosition(int position) 通过序号获取内购sku
16、private String getSkuType(String sku) 通过sku获取商品类型(订阅获取内购)inapp内购,subs订阅//接口设置
17、public GoogleBillingUtil setOnPurchaseFinishedListener(OnPurchaseFinishedListener onPurchaseFinishedListener) 购买回调接口
18、public GoogleBillingUtil setOnQueryFinishedListener(OnQueryFinishedListener onQueryFinishedListener) 商品信息查询接口
19、public GoogleBillingUtil setOnStartSetupFinishedListener(OnStartSetupFinishedListener onStartSetupFinishedListener) 服务初始化结果回调接口 //其他、内存
20、public void setIsAutoConsumeAsync(boolean isAutoConsumeAsync) 设置是否自动消耗商品
21、public static void cleanListener() 清除所有监听器,避免内存泄漏,回调错乱等问题。
22、public static void endConnection() 断开连接google服务(一般情况不建议调用该方法,让google保留连接是最好的选择。)

================版本说明=============== /**

  • Created by TJbaobao on 2017/11/2.
  • CSDN:http://blog.csdn.net/u013640004/article/details/78257536
  • 当前版本:V1.1.7
  • 更新日志:
  • v1.1.7 2019/01/05
  • 开放消耗结果监听器设置-{@link #setOnConsumeResponseListener}
  • v1.1.6 2018/09/05
  • 去掉我项目了的BaseApplication.getContext()的方法,初始现在需要传入一个Context,可以使用Application的Context
  • 对isGooglePlayServicesAvailable方法进行了说明,因为这个方法是要导入一个包才能使用的。
  • --> api "com.google.android.gms:play-services-location:11.8.0"
  • v1.1.5 2018/07/13
  • 优化-尽可能处理了一些可能造成的内存泄漏的问题。
  • 修改-查询成功接口增加一个String skuType,参数,各位在查询的时候需要判断skuType
  • 增加-增加两处接口为Null的Log提示,tag为GoogleBillingUtil。
  • V1.1.4 2018/01/03
  • 修改-实现单例模式,避免多实例导致的谷歌接口回调错乱问题。
  • V1.1.3 2017/12/19
  • 修复-服务启动失败时导致的空指针错误。
  • V1.1.2 2017/12/18
  • 修复-修复内购未被消耗的BUG。
  • 增加-每次启动都获取一次历史内购订单,并且全部消耗。
  • 增加-可以通过设置isAutoConsumeAsync来确定内购是否每次自动消耗。
  • 增加-将consumeAsync改为public,你可以手动调用消耗。
  • V1.1.1 2017/11/2
  • 升级-内购API版本为google最新版本。compile 'com.android.billingclient:billing:1.0'
  • 特性-不需要key了,不需要IInAppBillingService.aidl了,不需要那一大堆Utils了,创建新实例的时候必须要传入购买回调接口。
  • V1.0.3 2017/10/27
  • 增加-支持内购
  • V1.0.2 2017/09/11
  • 修复-修复BUG
  • v1.0.1 2017/07/29
  • 初始版本 */

GoogleBillingUtil.java

package com.tjbaobao.gitee.builling;import android.app.Activity;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.Log;
import com.android.billingclient.api.*;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;/*** Created by TJbaobao on 2017/11/2.* CSDN:http://blog.csdn.net/u013640004/article/details/78257536** 当前版本:V1.1.7* 更新日志:** v1.1.7 2019/01/05* 开放消耗结果监听器设置-{@link #setOnConsumeResponseListener}** v1.1.6 2018/09/05* 去掉我项目了的BaseApplication.getContext()的方法,初始现在需要传入一个Context,可以使用Application的Context* 对isGooglePlayServicesAvailable方法进行了说明,因为这个方法是要导入一个包才能使用的。* --> api "com.google.android.gms:play-services-location:11.8.0"** v1.1.5 2018/07/13* 优化-尽可能处理了一些可能造成的内存泄漏的问题。* 修改-查询成功接口增加一个String skuType,参数,各位在查询的时候需要判断skuType* 增加-增加两处接口为Null的Log提示,tag为GoogleBillingUtil。** V1.1.4 2018/01/03* 修改-实现单例模式,避免多实例导致的谷歌接口回调错乱问题。** V1.1.3 2017/12/19* 修复-服务启动失败时导致的空指针错误。** V1.1.2    2017/12/18* 修复-修复内购未被消耗的BUG。* 增加-每次启动都获取一次历史内购订单,并且全部消耗。* 增加-可以通过设置isAutoConsumeAsync来确定内购是否每次自动消耗。* 增加-将consumeAsync改为public,你可以手动调用消耗。** V1.1.1  2017/11/2* 升级-内购API版本为google最新版本。compile 'com.android.billingclient:billing:1.0'* 特性-不需要key了,不需要IInAppBillingService.aidl了,不需要那一大堆Utils了,创建新实例的时候必须要传入购买回调接口。** V1.0.3 2017/10/27* 增加-支持内购** V1.0.2  2017/09/11* 修复-修复BUG** v1.0.1 2017/07/29* 初始版本*/@SuppressWarnings("ALL")
public class GoogleBillingUtil {private static final String TAG = "GoogleBillingUtil";private static final boolean IS_DEBUG = false;private static String[] inAppSKUS = new String[]{};//内购IDprivate static String[] subsSKUS = new String[]{};//订阅IDpublic static final String BILLING_TYPE_INAPP = BillingClient.SkuType.INAPP;//内购public static final String BILLING_TYPE_SUBS = BillingClient.SkuType.SUBS;//订阅private static BillingClient mBillingClient;private static BillingClient.Builder builder ;private static OnPurchaseFinishedListener mOnPurchaseFinishedListener;private static OnStartSetupFinishedListener mOnStartSetupFinishedListener ;private static OnQueryFinishedListener mOnQueryFinishedListener;private static OnConsumeResponseListener mOnConsumeResponseListener;private boolean isAutoConsumeAsync = true;//是否在购买成功后自动消耗商品private static final GoogleBillingUtil mGoogleBillingUtil = new GoogleBillingUtil() ;private GoogleBillingUtil(){}/*** 设置skus* @param inAppSKUS 内购id* @param subsSKUS 订阅id*/public static void setSkus(@Nullable String[] inAppSKUS,@Nullable String[] subsSKUS){if(inAppSKUS!=null){GoogleBillingUtil.inAppSKUS = inAppSKUS;}if(subsSKUS!=null){GoogleBillingUtil.subsSKUS = subsSKUS;}}public static GoogleBillingUtil getInstance(){cleanListener();return mGoogleBillingUtil;}public GoogleBillingUtil build(Context context){if(mBillingClient==null){synchronized (mGoogleBillingUtil){if(mBillingClient==null){if(isGooglePlayServicesAvailable(context)){builder = BillingClient.newBuilder(context);mBillingClient = builder.setListener(mGoogleBillingUtil.new MyPurchasesUpdatedListener()).build();}else{if(IS_DEBUG){log("警告:GooglePlay服务处于不可用状态,请检查");}if(mOnStartSetupFinishedListener!=null){mOnStartSetupFinishedListener.onSetupError();}}}else{builder.setListener(mGoogleBillingUtil.new MyPurchasesUpdatedListener());}}}else{builder.setListener(mGoogleBillingUtil.new MyPurchasesUpdatedListener());}synchronized (mGoogleBillingUtil){if(mGoogleBillingUtil.startConnection()){mGoogleBillingUtil.queryInventoryInApp();mGoogleBillingUtil.queryInventorySubs();mGoogleBillingUtil.queryPurchasesInApp();}}return mGoogleBillingUtil;}public boolean startConnection(){if(mBillingClient==null){log("初始化失败:mBillingClient==null");return false;}if(!mBillingClient.isReady()){mBillingClient.startConnection(new BillingClientStateListener() {@Overridepublic void onBillingSetupFinished(@BillingClient.BillingResponse int billingResponseCode) {if (billingResponseCode == BillingClient.BillingResponse.OK) {queryInventoryInApp();queryInventorySubs();queryPurchasesInApp();if(mOnStartSetupFinishedListener!=null){mOnStartSetupFinishedListener.onSetupSuccess();}}else{log("初始化失败:onSetupFail:code="+billingResponseCode);if(mOnStartSetupFinishedListener!=null){mOnStartSetupFinishedListener.onSetupFail(billingResponseCode);}}}@Overridepublic void onBillingServiceDisconnected() {if(mOnStartSetupFinishedListener!=null){mOnStartSetupFinishedListener.onSetupError();}log("初始化失败:onBillingServiceDisconnected");}});return false;}else{return true;}}/*** Google购买商品回调接口(订阅和内购都走这个接口)*/private class MyPurchasesUpdatedListener implements PurchasesUpdatedListener{@Overridepublic void onPurchasesUpdated(int responseCode, @Nullable List<Purchase> list) {if(mOnPurchaseFinishedListener==null){if(IS_DEBUG){log("警告:接收到购买回调,但购买商品接口为Null,请设置购买接口。eg:setOnPurchaseFinishedListener()");}return ;}if(responseCode== BillingClient.BillingResponse.OK&&list!=null){if(isAutoConsumeAsync){//消耗商品for(Purchase purchase:list){String sku = purchase.getSku();if(sku!=null){String skuType = getSkuType(sku);if(skuType!=null){if(skuType.equals(BillingClient.SkuType.INAPP)){consumeAsync(purchase.getPurchaseToken());}}}}}mOnPurchaseFinishedListener.onPurchaseSuccess(list);}else{mOnPurchaseFinishedListener.onPurchaseFail(responseCode);}}}/*** 查询内购商品信息*/public void queryInventoryInApp(){queryInventory(BillingClient.SkuType.INAPP);}/*** 查询订阅商品信息*/public void queryInventorySubs(){queryInventory(BillingClient.SkuType.SUBS);}private void queryInventory(final String skuType) {Runnable runnable = new Runnable() {@Overridepublic void run() {if (mBillingClient == null){if(mOnQueryFinishedListener!=null){mOnQueryFinishedListener.onQueryError();}return ;}ArrayList<String> skuList = new ArrayList<>();if(skuType.equals(BillingClient.SkuType.INAPP)){Collections.addAll(skuList, inAppSKUS);}else if(skuType.equals(BillingClient.SkuType.SUBS)){Collections.addAll(skuList, subsSKUS);}SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();params.setSkusList(skuList).setType(skuType);mBillingClient.querySkuDetailsAsync(params.build(),new MySkuDetailsResponseListener(skuType));}};executeServiceRequest(runnable);}/*** Google查询商品信息回调接口*/private class MySkuDetailsResponseListener implements SkuDetailsResponseListener{private String skuType ;public MySkuDetailsResponseListener(String skuType) {this.skuType = skuType;}@Overridepublic void onSkuDetailsResponse(int responseCode , List<SkuDetails> list) {if(mOnQueryFinishedListener==null){if(IS_DEBUG) {log("警告:接收到查询商品回调,但查询商品接口为Null,请设置购买接口。eg:setOnQueryFinishedListener()");}return ;}if(responseCode== BillingClient.BillingResponse.OK&&list!=null){mOnQueryFinishedListener.onQuerySuccess(skuType,list);}else{mOnQueryFinishedListener.onQueryFail(responseCode);}}}/*** 发起内购* @param skuId* @return*/public void purchaseInApp(Activity activity,String skuId){purchase(activity,skuId, BillingClient.SkuType.INAPP);}/*** 发起订阅* @param skuId* @return*/public void purchaseSubs(Activity activity,String skuId){purchase(activity,skuId, BillingClient.SkuType.SUBS);}private void purchase(Activity activity,final String skuId,final String skuType){if(mBillingClient==null){if(mOnPurchaseFinishedListener!=null){mOnPurchaseFinishedListener.onPurchaseError();}return ;}if(startConnection()){BillingFlowParams flowParams = BillingFlowParams.newBuilder().setSku(skuId).setType(skuType).build();mBillingClient.launchBillingFlow(activity,flowParams);}else{if(mOnPurchaseFinishedListener!=null){mOnPurchaseFinishedListener.onPurchaseError();}}}/*** 消耗商品* @param purchaseToken*/public void consumeAsync(String purchaseToken){if(mBillingClient==null){return ;}mBillingClient.consumeAsync(purchaseToken, new MyConsumeResponseListener(mOnConsumeResponseListener));}/*** Googlg消耗商品回调*/private class MyConsumeResponseListener implements ConsumeResponseListener{private OnConsumeResponseListener onConsumeResponseListener;public MyConsumeResponseListener(OnConsumeResponseListener mOnConsumeResponseListener) {this.onConsumeResponseListener = mOnConsumeResponseListener;}@Overridepublic void onConsumeResponse(int responseCode, String purchaseToken) {if (responseCode == BillingClient.BillingResponse.OK) {if(onConsumeResponseListener!=null){onConsumeResponseListener.onConsumeSuccess(purchaseToken);}}else{if(onConsumeResponseListener!=null){onConsumeResponseListener.onConsumeFail(responseCode);}}}}/*** 获取已经内购的商品* @return*/public List<Purchase> queryPurchasesInApp(){return queryPurchases(BillingClient.SkuType.INAPP);}/*** 获取已经订阅的商品* @return*/public List<Purchase> queryPurchasesSubs(){return queryPurchases(BillingClient.SkuType.SUBS);}private List<Purchase> queryPurchases(String skuType){if(mBillingClient==null){return null;}if(!mBillingClient.isReady()){startConnection();}else{Purchase.PurchasesResult purchasesResult = mBillingClient.queryPurchases(skuType);if(purchasesResult!=null){if(purchasesResult.getResponseCode()== BillingClient.BillingResponse.OK){List<Purchase> purchaseList =  purchasesResult.getPurchasesList();if(isAutoConsumeAsync){if(purchaseList!=null){for(Purchase purchase:purchaseList){if(skuType.equals(BillingClient.SkuType.INAPP)){consumeAsync(purchase.getPurchaseToken());}}}}return purchaseList;}}}return null;}/*** 获取有效订阅的数量* @return -1查询失败,0没有有效订阅,>0具有有效的订阅*/public int getPurchasesSizeSubs(){List<Purchase> list = queryPurchasesSubs();if(list!=null){return list.size();}return -1;}/*** 通过sku获取订阅商品序号* @param sku* @return*/public int getSubsPositionBySku(String sku){return getPositionBySku(sku, BillingClient.SkuType.SUBS);}/*** 通过sku获取内购商品序号* @param sku* @return 成功返回需要 失败返回-1*/public int getInAppPositionBySku(String sku){return getPositionBySku(sku, BillingClient.SkuType.INAPP);}private int getPositionBySku(String sku,String skuType){if(skuType.equals(BillingClient.SkuType.INAPP)){int i = 0;for(String s:inAppSKUS){if(s.equals(sku)){return i;}i++;}}else if(skuType.equals(BillingClient.SkuType.SUBS)){int i = 0;for(String s:subsSKUS){if(s.equals(sku)){return i;}i++;}}return -1;}private void executeServiceRequest(final Runnable runnable){if(startConnection()){runnable.run();}}/*** 通过序号获取订阅sku* @param position* @return*/public String getSubsSkuByPosition(int position){if(position>=0&&position<subsSKUS.length){return subsSKUS[position];}else {return null;}}/*** 通过序号获取内购sku* @param position* @return*/public String getInAppSkuByPosition(int position){if(position>=0&&position<inAppSKUS.length){return inAppSKUS[position];}else{return null;}}/*** 通过sku获取商品类型(订阅获取内购)* @param sku* @return inapp内购,subs订阅*/public String getSkuType(String sku){if(Arrays.asList(inAppSKUS).contains(sku)){return BillingClient.SkuType.INAPP;}else if(Arrays.asList(subsSKUS).contains(sku)){return BillingClient.SkuType.SUBS;}return null;}/*** 检测GooglePlay服务是否可用(需要导入包api "com.google.android.gms:play-services-location:11.8.0",也可以不检查,跳过这个代码)* @param context* @return*/public static boolean isGooglePlayServicesAvailable(Context context){GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance();if(googleApiAvailability!=null){int resultCode = googleApiAvailability.isGooglePlayServicesAvailable(context);return resultCode == ConnectionResult.SUCCESS;}return false;//return true;//不检查直接跳过}public GoogleBillingUtil setOnQueryFinishedListener(OnQueryFinishedListener onQueryFinishedListener) {mOnQueryFinishedListener = onQueryFinishedListener;return mGoogleBillingUtil;}public GoogleBillingUtil setOnPurchaseFinishedListener(OnPurchaseFinishedListener onPurchaseFinishedListener) {mOnPurchaseFinishedListener = onPurchaseFinishedListener;return mGoogleBillingUtil;}public OnStartSetupFinishedListener getOnStartSetupFinishedListener() {return mOnStartSetupFinishedListener;}public GoogleBillingUtil setOnStartSetupFinishedListener(OnStartSetupFinishedListener onStartSetupFinishedListener) {mOnStartSetupFinishedListener = onStartSetupFinishedListener;return mGoogleBillingUtil;}public static OnConsumeResponseListener getmOnConsumeResponseListener() {return mOnConsumeResponseListener;}public GoogleBillingUtil setOnConsumeResponseListener(OnConsumeResponseListener onConsumeResponseListener) {mOnConsumeResponseListener = onConsumeResponseListener;return mGoogleBillingUtil;}/***  本工具查询回调接口*/public interface OnQueryFinishedListener{//Inapp和sub都走这个接口查询的时候一定要判断skuTypepublic void onQuerySuccess(String skuType, List<SkuDetails> list);public void onQueryFail(int responseCode);public void onQueryError();}/*** 本工具购买回调接口(内购与订阅都走这接口)*/public interface OnPurchaseFinishedListener{public void onPurchaseSuccess(List<Purchase> list);public void onPurchaseFail(int responseCode);public void onPurchaseError();}/*** google服务启动接口*/public interface OnStartSetupFinishedListener{public void onSetupSuccess();public void onSetupFail(int responseCode);public void onSetupError();}/*** 消耗回调监听器*/public interface OnConsumeResponseListener{public void onConsumeSuccess(String purchaseToken);public void onConsumeFail(int responseCode);}public boolean isReady() {return mBillingClient!=null&&mBillingClient.isReady();}public boolean isAutoConsumeAsync(){return isAutoConsumeAsync;}public void setIsAutoConsumeAsync(boolean isAutoConsumeAsync){this.isAutoConsumeAsync= isAutoConsumeAsync;}/*** 清除所有监听器,防止内存泄漏* 如果有多个页面使用了支付,需要确保上个页面的cleanListener在下一个页面的GoogleBillingUtil.getInstance()前使用。* 所以不建议放在onDestory里调用*/public static void cleanListener(){mOnPurchaseFinishedListener = null;mOnQueryFinishedListener = null;mOnStartSetupFinishedListener = null;mOnConsumeResponseListener = null;if(builder!=null){builder.setListener(null);}}/*** 断开连接google服务* 注意!!!一般情况不建议调用该方法,让google保留连接是最好的选择。*/public static void endConnection(){//注意!!!一般情况不建议调用该方法,让google保留连接是最好的选择。if(mBillingClient!=null){if(mBillingClient.isReady()){mBillingClient.endConnection();mBillingClient = null;}}}private static void log(String msg){if(IS_DEBUG){Log.e(TAG,msg);}}
}

GooglePlay内购In-app SDK接入相关推荐

  1. Unity接入GooglePlay内购V4(源生Android方式)

    Unity接GooglePlay In-App Billing坑还是蛮多的,各种坑. 接的方式目前来看有三种: 采用Unity IAP插件,开启Unity的IAP Service 采用Android源 ...

  2. GooglePlay内购接入错误Google Play In-app Billing API version is less than 3

    接入谷歌内购时,代码部分接入好了,于是打算开始测试,但是打开应用后初始化时一直提示错误:Google Play In-app Billing API version is less than 3.看名 ...

  3. GooglePlay内购In-app Billing 总结~

    最近因为项目需要加入googleplay的内购功能~所以网上找了很多资料,这里做个记号~ 官方的内购支付接入文档:https://developer.android.com/training/in-a ...

  4. GooglePlay内购服务器验单

    相关后台配置见另外一篇文章 https://blog.csdn.net/wuyutaoktm/article/details/122450878 package mainimport ("c ...

  5. Unity接入苹果内购

    文章目录 前言 一.苹果内购是什么? 二.Unity接入内购 1.开启内购 2.使用内购 总结 前言 Unity接入苹果内购前,需要提前配置好产品的内购ID以及拥有苹果账号,关于这个提前准备各位需要自 ...

  6. 解决某APP游戏内购

    对某APP内的道具购买进行破解 学习笔记三:对一款存在道具.关卡内购的APP进行破解使其道具.关卡购买免费化 一.将该未进行处理的APP通过模拟器安装使用 通过安装后的使用(购买其中的道具)发现该AP ...

  7. 苹果app商品定价_iOS 开发_2017苹果内购价格表

    [作者前言]:13年入圈,分享些本人工作中遇到的点点滴滴那些事儿,17年刚开始写博客,高手勿喷!以分享交流为主,欢迎各路豪杰点评改进! 1.应用场景: 使用苹果内购的APP/游戏 2.实现目标: 了解 ...

  8. swift5 接入内购全流程

    公司需要对接内购,顺便记录一下过程. 填写苹果协议 app store connect 协议 填写其中的付费 App,填写点公司名称.公司简介.公司帐号.公司之类的. 由于已经填写过了无法截图,可以去 ...

  9. iOS快速上手应用内购(IAP)附Demo

    前言:最近项目中接触到内购,本文主要介绍如何开发应用内购(In App Purchase),有一些是根据实际需求做的考虑,有不同的见解欢迎留言指教~本文demo:https://github.com/ ...

最新文章

  1. 实施ITIL十个需要知道的事情
  2. mysql压缩表语句_MYSQL静态表、动态表、压缩表总结
  3. 折半查找递归算法_两篇文章带你了解java基础算法之递归和折半查找
  4. python中的diff_python-Numpy和diff()
  5. 自欺欺人的使用 NSTimer 销毁
  6. SpringCloudGateway实现金丝雀发布_05
  7. 制作linux usb安裝,如何在Linux上安装和使用Etcher来制作Linux临场USB
  8. javascript中五种常见的DOM方法
  9. Centos下磁盘管理的常用命令记录(如查找大文件)
  10. Linux命令学习记录
  11. qt界面布局之如何修改qt5版本以上的左上角的图标
  12. 两个网卡做映射linux,linux多网卡的路由模式和桥接模式设置方法
  13. 安装office2013报安装程序找不到OneNote.zh-cn、安装源不存在
  14. 数据科学家面试常见的77个问题
  15. 文件系统模拟程序python_树莓派开发实战(第2版)
  16. 以梦为马,扬帆起航,双非人的2021,万字逐梦旅
  17. 分享html代码的博客,简单实用的HTML代码分享
  18. D3.js v5.0 旭日图
  19. 大白菜U盘安装win10操作系统
  20. python地图gps轨迹可视化_GPS轨迹数据可视化的三种途径

热门文章

  1. IDEA连接MySQL失败-[08S01] Communications link failure
  2. 一场为13条公链,5万多种通证赋能的全球开发者大赛正式开始!一等奖30万!...
  3. Pytest官网地址
  4. 分治算法解循环赛日程表问题
  5. Research Paper 论文写作 | 写好 Discussion
  6. blogger_如何使用Google Blogger创建博客
  7. CentOS7配置软件源
  8. 图解Hibernate中的三种状态(瞬时态,持久态,游离态|托管态)
  9. LBS定位技术之GPS(一)
  10. csdn的自动保存功能是摆设吗?我从下午2点写到现在的博客,最后点了下撤销,全给我删光了,你不能保存能不能别显示这个fw功能???????