一、前言:
在这我先提前说这么几个名词:
1.消耗
消耗是什么意思:消耗就相当于是订单确认,如果没有确认google会在3天后自动退款,同时这一笔物品就重新买不了
2.重试
重试是什么意思:就是重新去做处理,去查询谷歌这边,如果谷歌这边真的扣款成功,在去服务器这边查看是否成功)
3.依赖包版本选择
implementation 'com.android.billingclient:billing:3.0.0'
implementation 'com.android.billingclient:billing:4.0.0'
这2个包都是谷歌支付有关的,3.0 跟4.0 最大区别是3.0不能重复购买,只能一个个的购买,4.0版本可以购买多件(根据产品的需求 不需要一次性购买多件,我这次选择3.0)
二、google play 后台配置:
1、接入准备
- 1.申请一个google play开发者账号,这里我是有google play开发账号的,毕竟我们的APP是发谷歌市场的
- 2.提前准备好一个apk(不需要集成支付sdk,占位用),在google play控制台上传你的apk,这里你可以发封闭测试里面去,下面我会上图,不懂的看图
- 3.发布一个alpha或者beta的版本,发布之前需要点亮以下选项(提交商品详情内容)(确定内容分级)(选择发布范围)等,之后才能正常发布
- 4.添加测试人员,等应用审核通过之后,会得到一个地址,把地址发给对方,让对方点击同意加入测试即可
- 5.需要创建应用内商品(商品id,商品描述,定价),按提示填就可以了
- 6.在账户详细信息里面,添加许可测试的邮箱账号,许可测试响应改为 “RESPOND_NORMALLY/LICENSED”,点击保存,需要一两分钟生效,记得弄这一步,这个很坑,你不弄,你测试人员就一直不会出现测试卡测试的模式
- 7.检查你的包名和签名文件是否和Google Console 上面上传的apk包是否一致
- 8.检查版本号是否和Google console发布的apk版本是否一致
- 9.检查你是否可以购买,是否绑定了银行卡,手机支不支持Google支付,手机是否有Google服务
- 10.由于我是台湾上线APP,想测台币支付,我还得准备一个vpn,能选择线路台湾的
2、设定定价,就是商品的定价:
按图所示建立价格, 我这里有4个价格。具体建立很简单
建立产品:一个产品对应一个定价,比如我这里580台币对应406点。创建完后,如果没问题,一定要启用,不然app那边取不到数据,另外产品ID就是唯一,后面用在代码里取数据用的。关于产品id的设置,谷歌API中有这么一说,建议是按他要求的来,比较好
3、在账户详细信息里面,添加许可测试的邮箱账号,许可测试响应改为 “RESPOND_NORMALLY/LICENSED”,点击保存,需要一两分钟生效,记得弄这一步,这个很坑,你不弄,你测试人员就一直不会出现测试卡测试的模式
4、关于发一个占位包,跟设置测试人员
成功发布后,应用市场会出现
三、整体流程
看完流程图后,我们可以简单的总结下步骤,这里业务部分我就不细说了,这东西你得根据自己业务来调整
1.进入商品选择列表界面,选择需要购买的物品
2.根据选择的物品id,创建订单
3.初始化google支付,如果google已经连接,查询这个商品ID得到商品详情;如果没连接googlepay,调用连接
4.购买操作
5.onPurchasesUpdated通过购买回调,判断是否购买成功
6。如果购买成功,拿到Google支付返回的相关信息,在服务器进行验证操作。
7.如果服务器拿到你上传的相关信息和Google支付进行交互验证,验证谷歌扣款成功,服务器收款成功,说明支付成功,成功后,要做一次消耗操作,(消耗是什么意思:消耗就相当于是订单确认,如果没有确认google会在3天后自动退款,同时这一笔物品就重新买不了
8.如果服务器拿到你上传的相关信息和Google支付进行交互验证,验证谷歌扣款成功,服务器未收款到账,说明有问题,需要做重试操作,(重试是什么意思:就是重新去做处理,去查询谷歌这边,如果谷歌这边真的扣款成功,在去服务器这边查看是否成功)
注:这里第8步,我在这2个环境下,都做了对应的操作,增加了程序的友好体验, 第1:如果用户支付完成,就没管了,每次打开APP首页,我都会去帮他们做重试操作。这种用户是无感的,体验比较友好 第2: 如果用户支付完成,退出当前页面,然后再进来商品选择页面,点击同样的商品,这个时候由于还没成功,也没做消耗处理,是会有提示框弹窗,已拥有该商品,这个时候,我是会做重试的,如果成功,他下次在点击,就可以重新购买了
四、代码接入
目前已经升级到V3、V4版本,[AIDL](https://so.csdn.net/so/search?q=AIDL&spm=1001.2101.3001.7020)的方法已经过时了,并且未来的版本会将之移除,推荐使用使用 Google Play 结算库
1、添加依赖 跟 权限
implementation 'com.android.billingclient:billing:4.0.0'
<!--谷歌商店应用内购买结算需要的权限-->
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="com.farsitel.bazaar.permission.PAY_THROUGH_BAZAAR" />
2、创建连接
//连接到GooglePay
private void connectGooglePay(String skuId) {
//请求连接到GooglePay
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
int code = billingResult.getResponseCode();
if (code != BillingClient.BillingResponseCode.OK) {
String msg = billingResult.getDebugMessage();
Log.e(TAG, "连接到GooglePay失败 code = " + code + " msg = " + msg);
onFail();
return;
}
Log.e(TAG, "连接到GooglePay成功");
checkSku(skuId);
}
//连接失败
@Override
public void onBillingServiceDisconnected() {
Log.e(TAG, "连接到GooglePay失败,请重试");
}
});
}
3、查询
//查询商品
private void checkSku(String id) {
List<String> skuList = new ArrayList<>();
skuList.add(id);
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder()
.setSkusList(skuList)
.setType(BillingClient.SkuType.INAPP);
billingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(@NonNull BillingResult billingResult, @Nullable List<SkuDetails> list) {
int code = billingResult.getResponseCode();
if (code != BillingClient.BillingResponseCode.OK || list == null || list.isEmpty()) {
String msg = billingResult.getDebugMessage();
Log.e(TAG, "查询商品失败 code = " + code + " msg = " + msg);
onFail();
return;
}
Log.e(TAG, "查询商品成功");
buyIt(list.get(0));
}
});
}
4、购买
//购买
private void buyIt(SkuDetails skuDetails) {
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.build();
BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
int code = billingResult.getResponseCode();
if (code != BillingClient.BillingResponseCode.OK) {
String msg = billingResult.getDebugMessage();
Log.e(TAG, "购买商品失败 code = " + code + " msg = " + msg);
onFail();
return;
}
Log.e(TAG, "购买商品" + skuDetails.toString());
}
5、购买后的回调
@Override
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> list) {
int code = billingResult.getResponseCode();
String msg = billingResult.getDebugMessage();
Log.e(TAG, "onPurchasesUpdated:code = " + code + " msg = " + msg);
if (list != null) {
for (Purchase purchase : list) {
Log.e(TAG, "onPurchasesUpdated:" + purchase.toString());
}
}
if (code == BillingClient.BillingResponseCode.OK && list != null) {
Log.e(TAG, "支付成功");
onSuccess(list);
} else if (code == BillingClient.BillingResponseCode.USER_CANCELED) {
Log.e(TAG, "支付取消");
onFail();
} else {
Log.e(TAG, "支付失败:code = " + code + " msg = " + msg);
onFail();
}
}
6、消耗
/**
* 消耗商品:BillingClient.BillingResponseCode.OK
*
* int SERVICE_TIMEOUT = -3; //服务超时
* int FEATURE_NOT_SUPPORTED = -2; //不支持功能
* int SERVICE_DISCONNECTED = -1; //服务单元已断开
* int OK = 0; //成功
* int USER_CANCELED = 1; //用户按上一步或取消对话框
* int SERVICE_UNAVAILABLE = 2; //网络连接断开
* int BILLING_UNAVAILABLE = 3; //所请求的类型不支持 Google Play 结算服务 AIDL 版本
* int ITEM_UNAVAILABLE = 4; //请求的商品已不再出售。
* int DEVELOPER_ERROR = 5; //提供给 API 的参数无效。此错误也可能说明应用未针对结算服务正确签名或设置,或者在其清单中缺少必要的权限。
* int ERROR = 6; //API 操作期间出现严重错误
* int ITEM_ALREADY_OWNED = 7; //未能购买,因为已经拥有此商品
* int ITEM_NOT_OWNED = 8; //未能消费,因为尚未拥有此商品
*/
private void consume(List<Purchase> list) {
if (list == null || list.isEmpty() || billingClient == null) {
return;
}
for (Purchase purchase : list) {
billingClient.consumeAsync(ConsumeParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()).build(), new ConsumeResponseListener() {
@Override
public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
Log.e(TAG, "onConsumeResponse code = " + billingResult.getResponseCode() + " , msg = " + billingResult.getDebugMessage() + " , purchaseToken = " + purchaseToken);
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
//消耗成功,执行下一步
}
}
});
}
}
7、查询失败订单(支付成功未消耗)
/**
* 查询失败的订单
* skuType :,BillingClient.SkuType.INAPP; BillingClient.SkuType.SUBS
* 0:PurchaseState.UNSPECIFIED_STATE:未知状态
* 1:PurchaseState.PURCHASED:付款完成
* 2:PurchaseState.PENDING:购买正在等待付款完成。
*/
public void queryFailOrder(Activity activity, String skuType) {
MyToash.Log("pay", "-----查询需要补货的商品:");
if (mBillingClient != null) {
Purchase.PurchasesResult result = mBillingClient.queryPurchases(skuType);
if (BillingClient.BillingResponseCode.OK == result.getResponseCode()) {
for (Purchase purchase : result.getPurchasesList()) {
//PURCHASED --已购买
if (Purchase.PurchaseState.PURCHASED == purchase.getPurchaseState()) {
//MyToash.Log("pay", "----------需要补货的商品:");
//调用google去消费
getConsumeGoods(activity, purchase);
}
}
}
}
}
五、支付遇到的掉单问题处理:
1、分析失败的原因:
1、付款成功,消费失败,查询google未消费订单即可;
2、付款成功,消费失败(服务单元已断开-1,但是消费成功了,实际遇到的问题);
3、消费成功了,调用本地发放书币失败;
2、我的处理掉单的流程图
正常支付流程图
重试流程图
六、本人的逻辑处理:
1、GooglePayCommonUtils
/**
* google pay 公共方法调用
*/
public class GooglePayCommonUtils {
static Activity activity = null;
//google play的对象
public static GoogleBillingUtil googleBillingUtil = null;
// 购买回调接口
public static MyOnPurchaseFinishedListener mOnPurchaseFinishedListener = new MyOnPurchaseFinishedListener();
// 查询回调接口 - 返回无处理
public static MyOnQueryFinishedListener mOnQueryFinishedListener = new MyOnQueryFinishedListener();
// 启动结果回调接口-返回无处理
public static MyOnStartSetupFinishedListener mOnStartSetupFinishedListener = new MyOnStartSetupFinishedListener();
/**
* 初始化google play
*/
public static void initPlay(Activity mActivity) {
activity = mActivity;
googleBillingUtil = GoogleBillingUtil.getInstance()
// 注意,监听器设置是可选的,视个人需求设置。
.setOnPurchaseFinishedListener(mOnPurchaseFinishedListener)//购买回调接口
.setOnQueryFinishedListener(mOnQueryFinishedListener) //查询回调接口
.setOnStartSetupFinishedListener(mOnStartSetupFinishedListener) //启动结果回调接口
.build(activity);
}
/**
* google支付
* google_id:谷歌ID
* goods_id:商品ID
*/
public static void googlePay(Activity context,String google_id,String goods_id){
if (context != null&&googleBillingUtil!=null){
googleBillingUtil.purchaseInApp(activity, google_id, goods_id);
}
}
/**
* 查询未完成消耗的订单
*/
public static void chenkOrder(Activity context){
if (context != null&&googleBillingUtil!=null){
//调用线程池
ThreadPoolManager.Companion.getInstance().addTask("googlepay", new Runnable() {
@Override
public void run() {
//1、查询google未消费的商品
googleBillingUtil.queryFailOrder(activity, BillingClient.SkuType.INAPP);
//2、检查本地消耗成功的商品
googleBillingUtil.checkRecordLoaclConsumeGoods(activity);
//3、查询本地的失败订单;
googleBillingUtil.getLocalFailOrder(activity);
}
});
}
}
/**
* 更新用户第一次支付失败的状态
*/
public static void updateUserFailState(){
int is_recharge = MmkvUtils.decodeInt(CommonConstantUtils.IS_RECHARGE);
if (is_recharge<=0){
//支付数小于0
MmkvUtils.encode(CommonConstantUtils.FIRST_FAIL,true);
}else {
MmkvUtils.encode(CommonConstantUtils.FIRST_FAIL,false);
}
}
/**
* 购买商品回调接口
*/
public static class MyOnPurchaseFinishedListener implements GoogleBillingUtil.OnPurchaseFinishedListener {
@Override
public void onPurchaseSuccess(Purchase purchase) {
MyToash.Log("pay","--MyOnPurchaseFinishedListener--purchase="+purchase.toString());
//调用本地接口
googleBillingUtil.getConsumeGoods(activity,purchase);
}
@Override
public void onPurchaseFail(int responseCode) {
updateUserFailState();
MyToash.Log("pay","--MyOnPurchaseFinishedListener--responseCode="+responseCode);
}
@Override
public void onPurchaseError() {
updateUserFailState();
MyToash.Log("pay","--MyOnPurchaseFinishedListener--onPurchaseError=");
}
}
/**
* 服务初始化结果回调接口
*/
public static class MyOnStartSetupFinishedListener implements GoogleBillingUtil.OnStartSetupFinishedListener {
@Override
public void onSetupSuccess() {
}
@Override
public void onSetupFail(int responseCode) {
}
@Override
public void onSetupError() {
}
}
/**
* 查询商品信息回调接口
*/
public static class MyOnQueryFinishedListener implements GoogleBillingUtil.OnQueryFinishedListener {
@Override
public void onQuerySuccess(String skuType, List<SkuDetails> list) {
}
@Override
public void onQueryFail(int responseCode) {
//查询失败
}
@Override
public void onQueryError() {
//查询错误
}
}
/**
* 支付
*
* @param palChannelBean
* @param palChannelBean
*/
public static void payGood(Activity activity,PayBeen.ItemsBean itemsBean, PayBeen.ItemsBean.PalChannelBean palChannelBean) {
if (palChannelBean != null && itemsBean != null) {
// MyToash.Log("van---", itemsBean.google_id + " " + itemsBean.getFat_price());
switch (palChannelBean.getPay_type()) {
case 1:
MyToash.Log("pay", "--发起内购");
/**
* google_id: 谷歌ID
* goods_id:商品ID
*/
googleBillingUtil.purchaseInApp(activity, itemsBean.google_id, itemsBean.goods_id);
break;
case 2:
case 4:
// 应用内使用web
if (palChannelBean.getGateway() != null && !TextUtils.isEmpty(palChannelBean.getGateway())) {
Intent intent = new Intent();
intent.setClass(activity, WebViewActivity.class);
intent.putExtra("title", palChannelBean.getTitle());
if (palChannelBean.getGateway().contains("?")) {
intent.putExtra("url", palChannelBean.getGateway() +
"&token=" + UserUtils.getToken(activity) +
"&goods_id=" + itemsBean.goods_id);
} else {
intent.putExtra("url", palChannelBean.getGateway() +
"?token=" + UserUtils.getToken(activity) +
"&goods_id=" + itemsBean.goods_id);
}
if (palChannelBean.getPay_type() == 2) {
intent.putExtra("is_otherBrowser", true);
}
activity.startActivity(intent);
}
break;
}
} else {
MyToash.ToashError(activity, LanguageUtil.getString(activity, R.string.PayActivity_zhifucuowu));
}
}
}
2、GoogleBillingUtil
public class GoogleBillingUtil {
private static final String TAG = "GoogleBillingUtil";
private static final boolean IS_DEBUG = true;
public 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;
}
/**
* google play初始化
*
* @param context
* @return
*/
public GoogleBillingUtil build(Context context) {
if (mBillingClient == null) {
synchronized (mGoogleBillingUtil) {
if (mBillingClient == null) {
//检测GooglePlay服务是否可用
if (isGooglePlayServicesAvailable(context)) {
builder = BillingClient.newBuilder(context);
mBillingClient = builder.enablePendingPurchases().setListener(mGoogleBillingUtil.new MyPurchasesUpdatedListener()).build();
} else {
if (IS_DEBUG) {
log("警告:GooglePlay服务处于不可用状态,请检查");
}
if (mOnStartSetupFinishedListener != null) {
mOnStartSetupFinishedListener.onSetupError();
}
}
} else {
//Google购买商品回调接口(订阅和内购都走这个接口)
builder.setListener(mGoogleBillingUtil.new MyPurchasesUpdatedListener());
}
}
} else {
//Google购买商品回调接口(订阅和内购都走这个接口)
builder.setListener(mGoogleBillingUtil.new MyPurchasesUpdatedListener());
}
//请求连接到GooglePay
synchronized (mGoogleBillingUtil) {
if (mGoogleBillingUtil.startConnection()) {
/* mGoogleBillingUtil.queryInventoryInApp();
mGoogleBillingUtil.queryInventorySubs();
mGoogleBillingUtil.queryPurchasesInApp();*/
}
}
return mGoogleBillingUtil;
}
/**
* 请求连接到GooglePay
*
* @return
*/
public boolean startConnection() {
if (mBillingClient == null) {
MyToash.Log("pay", "初始化失败:mBillingClient==null");
return false;
}
MyToash.Log("pay", "--mBillingClient.isReady()-=" + mBillingClient.isReady());
if (!mBillingClient.isReady()) {
mBillingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(BillingResult billingResult) {
// MyToash.Log("van--", "--mBillingClient.startConnection-=" + billingResult.getResponseCode() + "===" + billingResult.getDebugMessage());
//连接到GooglePay成功
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
if (mOnStartSetupFinishedListener != null) {
mOnStartSetupFinishedListener.onSetupSuccess();
}
} else {
MyToash.Log("pay", "初始化失败:onSetupFail:code=" + billingResult.getResponseCode());
if (mOnStartSetupFinishedListener != null) {
mOnStartSetupFinishedListener.onSetupFail(billingResult.getResponseCode());
}
}
}
@Override
public void onBillingServiceDisconnected() {
if (mOnStartSetupFinishedListener != null) {
mOnStartSetupFinishedListener.onSetupError();
}
//log("初始化失败:onBillingServiceDisconnected");
MyToash.Log("pay", "初始化失败:onBillingServiceDisconnected");
}
});
return false;
} else {
return true;
}
}
/**
* getResponseCode值:
* <p>
* Google购买商品回调接口(订阅和内购都走这个接口)
* int SERVICE_TIMEOUT = -3;//服务超时
* int FEATURE_NOT_SUPPORTED = -2;//不支持功能
* int SERVICE_DISCONNECTED = -1;//服务单元已断开
* int OK = 0;//成功
* int USER_CANCELED = 1;//用户按上一步或取消对话框
* int SERVICE_UNAVAILABLE = 2;//网络连接断开
* int BILLING_UNAVAILABLE = 3;//所请求的类型不支持 Google Play 结算服务 AIDL 版本
* int ITEM_UNAVAILABLE = 4;//请求的商品已不再出售。
* int DEVELOPER_ERROR = 5;//提供给 API 的参数无效。此错误也可能说明应用未针对结算服务正确签名或设置,或者在其清单中缺少必要的权限。
* int ERROR = 6;//API 操作期间出现严重错误
* int ITEM_ALREADY_OWNED = 7;//未能购买,因为已经拥有此商品
* int ITEM_NOT_OWNED = 8;//未能消费,因为尚未拥有此商品
*/
private class MyPurchasesUpdatedListener implements PurchasesUpdatedListener {
@Override
public void onPurchasesUpdated(BillingResult billingResult, @Nullable List<Purchase> list) {
MyToash.Log("pay", "--MyPurchasesUpdatedListener--调用本地接口");
//支付成功
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && list != null && !list.isEmpty()) {
MyToash.Log("pay", "--onPurchasesUpdated--=" + list.size());
//回调支付成功
if (mOnPurchaseFinishedListener != null) {
//消耗商品
Purchase purchase = list.get(0);
mOnPurchaseFinishedListener.onPurchaseSuccess(purchase);
}
} else {
MyToash.Log("pay", "--onPurchasesUpdatedFail--=" + billingResult.getResponseCode());
mOnPurchaseFinishedListener.onPurchaseFail(billingResult.getResponseCode());
}
}
}
/**
* 查询内购商品信息
*/
public void queryInventoryInApp() {
queryInventory(BillingClient.SkuType.INAPP);
}
/**
* 查询订阅商品信息
*/
public void queryInventorySubs() {
queryInventory(BillingClient.SkuType.SUBS);
}
private void queryInventory(final String skuType) {
/* Runnable runnable = new Runnable() {
@Override
public 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;
}
@Override
public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> list) {
if (mOnQueryFinishedListener == null) {
if (IS_DEBUG) {
log("警告:接收到查询商品回调,但查询商品接口为Null,请设置购买接口。eg:setOnQueryFinishedListener()");
}
return;
}
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && list != null) {
mOnQueryFinishedListener.onQuerySuccess(skuType, list);
} else {
mOnQueryFinishedListener.onQueryFail(billingResult.getResponseCode());
}
}
}
/**
* 发起内购
*
* @param activity
* @param skuId:googleID
* @param goods_id:商品ID
*/
public void purchaseInApp(Activity activity, String skuId, String goods_id) {
//创建本地订单
WaitDialogUtils.showDialog(activity);
getCreateOrder(activity, goods_id, "1", new CallCheckOrder() {
@Override
public void call(String result) {
purchase(activity, skuId, BillingClient.SkuType.INAPP);
}
});
}
/**
* 发起订阅
*
* @param skuId
* @return
*/
public void purchaseSubs(Activity activity, String skuId, String goods_id) {
//创建本地订单
WaitDialogUtils.showDialog(activity);
getCreateOrder(activity, skuId, "1", new CallCheckOrder() {
@Override
public void call(String result) {
purchase(activity, skuId, BillingClient.SkuType.SUBS);
}
});
}
/**
* 发起google play支付
*
* @param activity
* @param skuId
* @param skuType
*/
private void purchase(Activity activity, final String skuId, final String skuType) {
if (mBillingClient == null) {
if (mOnPurchaseFinishedListener != null) {
mOnPurchaseFinishedListener.onPurchaseError();
MyToash.Log("pay", "-purchase-onPurchaseError");
}
return;
}
if (startConnection()) {
List<String> skuList = new ArrayList<>();
skuList.add(skuId);//商品的id
skuList.add("gas");// 这个参数不能为空,值随便传
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
MyToash.Log("pay", "-开始调用google查询商品接口");
//querySkuDetailsAsync 查询方法,list集合中传入商品id,谷歌后台-》应用内商品-》具体商品
mBillingClient.querySkuDetailsAsync(params.build(),
new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(BillingResult billingResult,
List<SkuDetails> skuDetailsList) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && skuDetailsList != null) {
// MyToash.Log("pay", "skuDetailsList---=" + skuDetailsList.toString());
for (SkuDetails skuDetailsBean : skuDetailsList) {
String sku = skuDetailsBean.getSku();//商品id
if (skuId.equals(sku)) {
MyToash.Log("pay", "-开始调用google支付弹窗");
/**
* 真正的购买方法
*/
BillingFlowParams purchaseParams =
BillingFlowParams.newBuilder()
.setSkuDetails(skuDetailsBean)
.build();
//发起google支付弹窗
mBillingClient.launchBillingFlow(activity, purchaseParams);
}
}
} else {
MyToash.Log("pay", "goods search fail");
}
}
});
} else {
if (mOnPurchaseFinishedListener != null) {
MyToash.Log("pay", "---google连接失败");
mOnPurchaseFinishedListener.onPurchaseError();
}
}
}
/**
* 消耗商品
*
* @param purchaseToken
* int SERVICE_TIMEOUT = -3; //服务超时
* int FEATURE_NOT_SUPPORTED = -2; //不支持功能
* int SERVICE_DISCONNECTED = -1; //服务单元已断开
* int OK = 0; //成功
* int USER_CANCELED = 1; //用户按上一步或取消对话框
* int SERVICE_UNAVAILABLE = 2; //网络连接断开
* int BILLING_UNAVAILABLE = 3; //所请求的类型不支持 Google Play 结算服务 AIDL 版本
* int ITEM_UNAVAILABLE = 4; //请求的商品已不再出售。
* int DEVELOPER_ERROR = 5; //提供给 API 的参数无效。此错误也可能说明应用未针对结算服务正确签名或设置,或者在其清单中缺少必要的权限。
* int ERROR = 6; //API 操作期间出现严重错误
* int ITEM_ALREADY_OWNED = 7; //未能购买,因为已经拥有此商品
* int ITEM_NOT_OWNED = 8; //未能消费,因为尚未拥有此商品
*/
public void consumeAsync(Activity activity, ConsumeParams consumeParams, Purchase purchase) {
if (mBillingClient == null) {
return;
}
//本地记录消费的商品
saveRecordLoaclConsumeGoods(activity, purchase, 1);
mBillingClient.consumeAsync(consumeParams, new ConsumeResponseListener() {
@Override
public void onConsumeResponse(@NonNull BillingResult billingResult, @NonNull String s) {
// MyToash.Log("van---", "--consumeAsync--=" + billingResult.toString() + "---" + s);
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
MyToash.Log("pay", "-----消耗商品成功");
// ----------- 沙盒代码 - 正式环境要上报-------- -
if (BaseConfig.INSTANCE.getCurrentEnvironment()){
String pId = purchase.getSkus().get(0);
String price = CommonOkHttpUtils.INSTANCE.getPayPrice(pId);
MyToash.Log("pay", "-----消耗商品成功 "+"价格:"+price);
String productToken = purchase.getPurchaseToken();
String token = UserUtils.getToken(activity);
AdjustEvent event = new AdjustEvent(Constant.MD_ADJUST_czcg);
event.setRevenue(Double.parseDouble(price),"USD");
event.addCallbackParameter("productId", pId);
event.addCallbackParameter("productToken", productToken);
// event.addCallbackParameter("goods_id",goods_id);
event.addCallbackParameter("token", token);
event.addCallbackParameter("content_type", "1");
event.addCallbackParameter("book_id", ShareUitls.getString(activity, BaseKey.SP_BOOKID, ""));
event.addCallbackParameter("packageName", purchase.getPackageName());
Adjust.trackEvent(event);
}
//请求本地接口
getHttpPay(activity, purchase);
//移除
saveRecordLoaclConsumeGoods(activity, purchase, 2);
} else {
MyToash.Log("pay", "-----消耗商品失败" + billingResult.toString() + "---" + s + "--code:" + billingResult.getResponseCode());
}
}
});
}
/**
* 记录本地消费的商品
*
* @param activity
* @param purchase
* @param type: 1:是保存;2:移除
*/
private void saveRecordLoaclConsumeGoods(Activity activity, Purchase purchase, int type) {
try {
if (purchase != null) {
String uid_key = UserUtils.getUID(activity) + CommonConstantUtils.CONSUME;
List<String> list = new ArrayList<>();
//获取存储的值
String lastJson = MmkvUtils.decodeString(uid_key);
String pId = purchase.getSkus().get(0);
String purchaseToken = purchase.getPurchaseToken();
String packageName = purchase.getPackageName();
//键值对唯一的key
String onlyKey = purchaseToken + CommonConstantUtils.CONSUME;
if (type == 1) { //保存
//不是空
if (!lastJson.isEmpty()) {
List<String> list2 = GsonUtil.GsonToList(lastJson, String.class);
for (int i = 0; i < list2.size(); i++) {
String data = list2.get(i);
OrderFailBean bean = GsonUtil.GsonToBean(data, OrderFailBean.class);
String tokenKey = bean.getPurchaseToken() + CommonConstantUtils.CONSUME;
//是否要保存一条数据
if (!tokenKey.equals(onlyKey)) {
list.add(data);
}
}
}
//没有相同单据,保存
HashMap map = new HashMap();
map.put("pId", pId);
map.put("purchaseToken", purchaseToken);
map.put("packageName", packageName);
list.add(GsonUtil.BeanToJson(map));
String json = GsonUtil.BeanToJson(list);
//保存上传失败的订单
MmkvUtils.encode(uid_key, json);
MyToash.Log("pay", "--保存消耗的商品json:" + purchaseToken);
// MyToash.Log("pay", "--保存消耗的商品json:" + json);
} else if (type == 2) { //移除
//不是空
if (!lastJson.isEmpty()) {
int currentIndex = -1;
List<String> list3 = GsonUtil.GsonToList(lastJson, String.class);
for (int i = 0; i < list3.size(); i++) {
String data = list3.get(i);
list.add(data);
OrderFailBean bean = GsonUtil.GsonToBean(data, OrderFailBean.class);
String tokenKey = bean.getPurchaseToken() + CommonConstantUtils.CONSUME;
if (tokenKey.equals(onlyKey)) {
currentIndex = i;
}
}
if (currentIndex != -1) {
list.remove(currentIndex);
String json = GsonUtil.BeanToJson(list);
//保存上传失败的订单
MmkvUtils.encode(uid_key, json);
MyToash.Log("pay", "--移除消耗的商品json:" + json);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 查询本地消费商品未返回数据
*
* @param type
* @param activity
* @param purchase
*/
public void checkRecordLoaclConsumeGoods(Activity activity) {
try {
String uid = UserUtils.getUID(activity);
String uid_key = UserUtils.getUID(activity) + CommonConstantUtils.CONSUME;
List<String> list = new ArrayList<>();
//获取存储的值
String lastJson = MmkvUtils.decodeString(uid_key);
MyToash.Log("pay", "--查询本地消费后商品未返回数据lastJson:" + lastJson);
if (!lastJson.isEmpty()) {
//不是空
list = GsonUtil.GsonToList(lastJson, String.class);
if (list != null && list.size() > 0) {
//上传
for (int i = 0; i < list.size(); i++) {
String data = list.get(i);
OrderFailBean bean = GsonUtil.GsonToBean(data, OrderFailBean.class);
String pId = bean.getpId();
String purchaseToken = bean.getPurchaseToken();
String packageName = bean.getPackageName();
MyToash.Log("pay", "--查询本地消费后商品未返回数据上传本地单据:" + purchaseToken);
//上传本地单据
UploadLocalFailOrder(activity, uid, pId, packageName, purchaseToken);
Thread.sleep(1000);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取已经内购的商品
*
* @return
*/
public List<Purchase> queryPurchasesInApp() {
return queryPurchases(BillingClient.SkuType.INAPP);
}
/**
* 获取已经订阅的商品
*
* @return
*/
public List<Purchase> queryPurchasesSubs() {
return queryPurchases(BillingClient.SkuType.SUBS);
}
/**
* 查询最近的购买交易
*
* @param skuType
* @return
*/
private List<Purchase> queryPurchases(String skuType) {
if (mBillingClient == null) {
return null;
}
if (!mBillingClient.isReady()) {
//如果断开google连接,重新开始连接
startConnection();
} else {
Purchase.PurchasesResult purchasesResult = mBillingClient.queryPurchases(skuType);
if (purchasesResult != null) {
if (purchasesResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
List<Purchase> purchaseList = purchasesResult.getPurchasesList();
/* if (isAutoConsumeAsync) {
if (purchaseList != null) {
for (Purchase purchase : purchaseList) {
if (skuType.equals(purchase.getSku())) {
ConsumeParams.Builder consumeParams = ConsumeParams.newBuilder();
consumeParams.setPurchaseToken(purchase.getPurchaseToken());
*//* consumeParams
consumeParams.setDeveloperPayload(purchase.getDeveloperPayload());*//*
consumeAsync(consumeParams.build(), purchase);
}
}
}
}*/
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;
}*/
return null;
}
/**
* 通过序号获取内购sku
*
* @param position
* @return
*/
public String getInAppSkuByPosition(int position) {
/* if (position >= 0 && position < inAppSKUS.length) {
return inAppSKUS[position];
} else {
return null;
}*/
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_img 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都走这个接口查询的时候一定要判断skuType
public void onQuerySuccess(String skuType, List<SkuDetails> list);
public void onQueryFail(int responseCode);
public void onQueryError();
}
/**
* 本工具购买回调接口(内购与订阅都走这接口)
*/
public interface OnPurchaseFinishedListener {
public void onPurchaseSuccess(Purchase purchase);
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.i(TAG, msg);
}
}
/**
* 查询失败的订单
* skuType :,BillingClient.SkuType.INAPP; BillingClient.SkuType.SUBS
* 0:PurchaseState.UNSPECIFIED_STATE:未知状态
* 1:PurchaseState.PURCHASED:付款完成
* 2:PurchaseState.PENDING:购买正在等待付款完成。
*/
public void queryFailOrder(Activity activity, String skuType) {
MyToash.Log("pay", "-----查询需要补货的商品:");
if (mBillingClient != null) {
Purchase.PurchasesResult result = mBillingClient.queryPurchases(skuType);
if (BillingClient.BillingResponseCode.OK == result.getResponseCode()) {
for (Purchase purchase : result.getPurchasesList()) {
//PURCHASED --已购买
if (Purchase.PurchaseState.PURCHASED == purchase.getPurchaseState()) {
//MyToash.Log("pay", "----------需要补货的商品:");
//调用google去消费
getConsumeGoods(activity, purchase);
}
}
}
}
}
/**
* 公共消费商品接口
*/
public void getConsumeGoods(Activity activity, Purchase purchase) {
if (purchase != null) {
MyToash.Log("pay", "-----开始消耗商品:" + purchase.toString());
//本地发送书券成功之后,调用消耗接口
ConsumeParams.Builder consumeParams = ConsumeParams.newBuilder();
consumeParams.setPurchaseToken(purchase.getPurchaseToken());
//调用消耗商品方法
consumeAsync(activity, consumeParams.build(), purchase);
}
}
/**
* 正常流程-调用本地接口发送书券和书币
*/
public void getHttpPay(Activity activity, Purchase purchase) {
if (purchase != null) {
String pId = purchase.getSkus().get(0);
String purchaseToken = purchase.getPurchaseToken();
String packageName = purchase.getPackageName();
//保存本地单据
saveLocalFaileOrder(activity, purchase);
//调用本地发书券接口
GoPay.httpPay(activity, pId, purchaseToken, "", packageName, new GooglePayActivity.UpPay() {
@Override
public void paySuccess(String success) {
MyToash.Log("pay", "--本地接口调用成功:" + success);
//WaitDialogUtils.dismissDialog();
ShareUitls.putString(activity, BaseKey.SP_BOOKID, "");
ShareUitls.putString(activity, "goods_id", null);
ShareUitls.putString(activity, "productId", null);
ShareUitls.putString(activity, "productToken", null);
//通知刷新页面
EventBus.getDefault().post(new RefreshMine());
//成功提示
MyToash.ToashSuccess(activity, success);
//删除本地的数据
deleteLocalFaileOrder(activity, purchaseToken);
}
@Override
public void payFail(String msg) {
//本地接口调用失败
MyToash.Log("pay", "----本地接口调用失败:" + msg);
}
});
}
}
/**
* 保存本地失败的单据
*
* @param activity
*/
private void saveLocalFaileOrder(Activity activity, Purchase purchase) {
try {
String pId = purchase.getSkus().get(0);
String purchaseToken = purchase.getPurchaseToken();
String packageName = purchase.getPackageName();
//用户id
String uid = UserUtils.getUID(activity);
List<String> list = new ArrayList<>();
//获取存储的值
String lastJson = MmkvUtils.decodeString(uid);
if (!lastJson.isEmpty()) {
//不是空,只有第一次请求失败保存
List<String> list2 = GsonUtil.GsonToList(lastJson, String.class);
for (int i = 0; i < list2.size(); i++) {
String data = list2.get(i);
list.add(data);
}
}
//没有相同单据,保存
HashMap map = new HashMap();
map.put("pId", pId);
map.put("purchaseToken", purchaseToken);
map.put("packageName", packageName);
list.add(GsonUtil.BeanToJson(map));
String json = GsonUtil.BeanToJson(list);
//保存上传失败的订单
MmkvUtils.encode(uid, json);
MyToash.Log("pay", "----保存上传失败的订单json:" + json);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除本地失败的单据
*
* @param activity
*/
private void deleteLocalFaileOrder(Activity activity, String purchaseToken) {
try {
//用户id
String uid = UserUtils.getUID(activity);
String lastJson = MmkvUtils.decodeString(uid);
if (!lastJson.isEmpty()) {
MyToash.Log("pay", "----查询准备要删除上传失败的订单:" + lastJson);
//不是空
List<String> list = GsonUtil.GsonToList(lastJson, String.class);
//是否有相等的下标
int index = -1;
for (int i = 0; i < list.size(); i++) {
String data = list.get(i);
OrderFailBean bean = GsonUtil.GsonToBean(data, OrderFailBean.class);
String token = bean.getPurchaseToken();
if (purchaseToken.equals(token)) {
index = i;
}
}
//删除数据
if (index != -1) {
list.remove(index);
String json = GsonUtil.BeanToJson(list);
//保存数据
MmkvUtils.encode(uid, json);
MyToash.Log("pay", "----删除上传失败的订单:" + json);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 查询订单失败--调用本地接口发送书券和书币
*/
public void getLocalFailOrder(Activity activity) {
try {
//用户id
String uid = UserUtils.getUID(activity);
List<String> list = new ArrayList<>();
//获取存储的值
String lastJson = MmkvUtils.decodeString(uid);
MyToash.Log("pay", "---查询失败的订单lastJson:" + lastJson);
if (!lastJson.isEmpty()) {
//不是空
list = GsonUtil.GsonToList(lastJson, String.class);
for (int i = 0; i < list.size(); i++) {
String data = list.get(i);
OrderFailBean bean = GsonUtil.GsonToBean(data, OrderFailBean.class);
String pId = bean.getpId();
String purchaseToken = bean.getPurchaseToken();
String packageName = bean.getPackageName();
//上传失败的单据
UploadLocalFailOrder(activity, uid, pId, packageName, purchaseToken);
Thread.sleep(1000);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 上传本地单据
*
* @param pId
* @param packageName
* @param purchaseToken
*/
private void UploadLocalFailOrder(Activity activity, String uid, String pId, String packageName, String purchaseToken) {
try {
//调用本地发书券接口
GoPay.httpPay(activity, pId, purchaseToken, "", packageName, new GooglePayActivity.UpPay() {
@Override
public void paySuccess(String success) {
MyToash.Log("pay", "后台上传失败订单成功:" + success);
//WaitDialogUtils.dismissDialog();
ShareUitls.putString(activity, BaseKey.SP_BOOKID, "");
ShareUitls.putString(activity, "goods_id", null);
ShareUitls.putString(activity, "productId", null);
ShareUitls.putString(activity, "productToken", null);
//通知刷新页面
EventBus.getDefault().post(new RefreshMine());
//删除本地的数据
deleteLocalFaileOrder(activity, purchaseToken);
//移除消费无响应数据
deleteRecordLoaclConsumeGoods(activity, pId, purchaseToken, packageName);
}
@Override
public void payFail(String msg) {
//本地接口调用失败
try {
if (!TextUtils.isEmpty(msg)) {
int subIndex = msg.indexOf(",");
if (subIndex > 0) {
String code = msg.substring(0, subIndex);
String message = msg.substring(subIndex, msg.length());
if ("806".equals(code)) {
//删除本地的数据
deleteLocalFaileOrder(activity, purchaseToken);
//移除消费无响应数据
deleteRecordLoaclConsumeGoods(activity, pId, purchaseToken, packageName);
}
}
}
MyToash.Log("pay", "后台上传失败订单失败:" + msg);
} catch (Exception e) {
e.printStackTrace();
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 新-只删除消费商品无响应的状态
*
* @param activity
* @param lastJson
* @param pId
* @param purchaseToken
* @param packageName
*/
private void deleteRecordLoaclConsumeGoods(Activity activity, String pId, String purchaseToken, String packageName) {
try {
String uid_key = UserUtils.getUID(activity) + CommonConstantUtils.CONSUME;
List<String> list = new ArrayList<>();
//获取存储的值
String lastJson = MmkvUtils.decodeString(uid_key);
//不是空
if (!lastJson.isEmpty()) {
int currentIndex = -1;
List<String> list3 = GsonUtil.GsonToList(lastJson, String.class);
for (int i = 0; i < list3.size(); i++) {
String data = list3.get(i);
list.add(data);
OrderFailBean bean = GsonUtil.GsonToBean(data, OrderFailBean.class);
String tokenKey = bean.getPurchaseToken() + CommonConstantUtils.CONSUME;
if ((tokenKey).equals(purchaseToken + CommonConstantUtils.CONSUME)) {
currentIndex = i;
}
}
if (currentIndex != -1) {
list.remove(currentIndex);
String json = GsonUtil.BeanToJson(list);
//保存上传失败的订单
MmkvUtils.encode(uid_key, json);
MyToash.Log("pay", "--移除消耗的商品json:" + json);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 调用支付之前创建订单
* goods_id:商品ID
* content_type:内容类型 1小说
*/
public void getCreateOrder(Activity activity, String goods_id, String content_type, CallCheckOrder CallCheckOrder) {
ReaderParams params = new ReaderParams(activity);
params.putExtraParams("goods_id", goods_id);
params.putExtraParams("content_type", content_type);
params.putExtraParams("book_id", ShareUitls.getString(activity, BaseKey.SP_BOOKID, ""));
String json = params.generateParamsJson();
//调用本地发书券接口
//MyToash.Log("lyy", "--json:" + json);
HttpUtils.getInstance().sendRequestRequestParams(activity, Api.mCreateOrderUrl, json, new HttpUtils.ResponseListener() {
@Override
public void onResponse(final String result) {
WaitDialogUtils.dismissDialog();
MyToash.Log("pay", "--创建订单成功" + result);
if (CallCheckOrder != null) {
CallCheckOrder.call("success");
}
}
@Override
public void onErrorResponse(String error) {
WaitDialogUtils.dismissDialog();
MyToash.Log("pay", "--创建订单失败" + error);
}
}
);
}
public interface CallCheckOrder {
void call(String result);
}
}
参考链接:
- 地址1:https://blog.csdn.net/yangbin0513/article/details/123591922
- 地址2:https://blog.csdn.net/yangbin0513/article/details/123593779?spm=1001.2014.3001.5502
- 地址3:https://www.cnblogs.com/fnlingnzb-learner/p/16385685.html
1、MmkvUtils 使用和初始化:
//mmkv
implementation 'com.tencent:mmkv-static:1.2.7'
//application中mmkv初始化
MMKV.initialize(context)
MmkvUtils.getInstance()
//使用
//存储
MmkvUtils.encode("key",value);
//获取,存什么类型,获取的时候是什么类型
val value2 = MmkvUtils.decodeInt("key");
2、MmkvUtils 工具类:
package com.kana.crazytv.app.util;
import android.os.Parcelable;
import com.tencent.mmkv.MMKV;
import java.util.Collections;
import java.util.Set;
public class MmkvUtils {
//--------封装的方法---------
private static MmkvUtils mInstance;
private static MMKV mv;
private MmkvUtils() {
mv = MMKV.defaultMMKV();
}
/**
* 初始化MMKV,只需要初始化一次,建议在Application中初始化
*
*/
public static MmkvUtils getInstance() {
if (mInstance == null) {
synchronized (MmkvUtils.class) {
if (mInstance == null) {
mInstance = new MmkvUtils();
}
}
}
return mInstance;
}
/**
* 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
*
* @param key
* @param object
*/
public static void encode(String key, Object object) {
if (object instanceof String) {
mv.encode(key, (String) object);
} else if (object instanceof Integer) {
mv.encode(key, (Integer) object);
} else if (object instanceof Boolean) {
mv.encode(key, (Boolean) object);
} else if (object instanceof Float) {
mv.encode(key, (Float) object);
} else if (object instanceof Long) {
mv.encode(key, (Long) object);
} else if (object instanceof Double) {
mv.encode(key, (Double) object);
} else if (object instanceof byte[] ) {
mv.encode(key, (byte[]) object);
} else {
mv.encode(key, object.toString());
}
}
public static void encodeSet(String key, Set<String> sets) {
mv.encode(key, sets);
}
public static void encodeParcelable(String key, Parcelable obj) {
mv.encode(key, obj);
}
/**
* 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值
*/
public static Integer decodeInt(String key) {
return mv.decodeInt(key, 0);
}
public static Double decodeDouble(String key) {
return mv.decodeDouble(key, 0.00);
}
public static Long decodeLong(String key) {
return mv.decodeLong(key, 0L);
}
public static Boolean decodeBoolean(String key) {
return mv.decodeBool(key, false);
}
public static Float decodeFloat(String key) {
return mv.decodeFloat(key, 0F);
}
public static byte[] decodeBytes(String key) {
return mv.decodeBytes(key);
}
public static String decodeString(String key) {
return mv.decodeString(key,"");
}
public static Set<String> decodeStringSet(String key) {
return mv.decodeStringSet(key, Collections.<String>emptySet());
}
public static Parcelable decodeParcelable(String key) {
return mv.decodeParcelable(key, null);
}
/**
* 移除某个key对
*
* @param key
*/
public static void removeKey(String key) {
mv.removeValueForKey(key);
}
/**
* 清除所有key
*/
public static void clearAll() {
mv.clearAll();
}
/**
* 是否包含某个key
*/
public static boolean containsKey(String key) {
return mv.containsKey(key);
}
}