Android应用内支付(IAB)多SKU购买提示SKU为空的代码修复咨询
问题原因
你遇到的the SKU cannot be null报错是因为调用launchBillingFlow时传入的SkuDetails对象为空,核心原因有三个:
- 商品详情查询失败/返回不全时,直接覆盖了本地保存的商品详情Map,导致已有的商品信息丢失
- BillingClient服务断开后没有自动重连逻辑,后续的商品详情查询直接失败返回空
- 点击按钮时只判断了商品Map是否为空,没有判断目标SKU是否存在于Map中,直接调用
get方法返回空值
修复方案
一、修改Activity类代码
- 调整
purchase_action方法,增加目标SKU存在性校验,不存在时主动重新拉取商品信息
public void purchase_action(String pur_item) { button_pressed = pur_item; SkuDetails targetSku = skuDetailsHashMap.get(pur_item); if(targetSku != null) { iapHelper.launchBillingFLow(targetSku); Utilities.system_toast(Settings2.this, "purchase action", "going through"); } else { Utilities.system_toast(Settings2.this, "正在获取商品信息,请稍后重试", Toast.LENGTH_SHORT); // 主动触发重新拉取SKU详情 iapHelper.getSKUDetails(skuList); } }
- 调整
onSkuListResponse方法,改为合并新拉取的商品信息而不是直接覆盖,避免查询失败清空原有数据
@Override public void onSkuListResponse(HashMap<String, SkuDetails> newSkuDetails) { if (newSkuDetails != null && !newSkuDetails.isEmpty()) { skuDetailsHashMap.putAll(newSkuDetails); } }
二、修改IabHelper类代码
- 给
launchBillingFLow方法增加空校验,避免传入空值触发崩溃
public void launchBillingFLow(final SkuDetails skuDetails) { if(mBillingClient.isReady() && skuDetails != null){ BillingFlowParams mBillingFlowParams = BillingFlowParams.newBuilder().setSkuDetails(skuDetails).build(); mBillingClient.launchBillingFlow((Activity) context, mBillingFlowParams); } else if (skuDetails == null) { Log.e(TAG, "launchBillingFLow failed: skuDetails is null"); } }
- 补全服务断开后的自动重连逻辑
@Override public void onBillingServiceDisconnected() { Log.d(TAG, "onBillingServiceDisconnected: try to reconnect"); // 延迟1秒重连,避免频繁请求 new Handler(Looper.getMainLooper()).postDelayed(() -> { if (mBillingClient != null && !mBillingClient.isReady()) { startConnection(); } }, 1000); }
- 给
getSKUDetails方法增加服务就绪校验,未就绪时先触发重连
public void getSKUDetails(List<String> skuList) { if (!mBillingClient.isReady()) { startConnection(); return; } // 原有方法逻辑保持不变 final HashMap<String, SkuDetails> skuDetailsHashMap = new HashMap<>(); SkuDetailsParams skuParams = SkuDetailsParams.newBuilder().setType(BillingClient.SkuType.INAPP).setSkusList(skuList).build(); mBillingClient.querySkuDetailsAsync(skuParams, new SkuDetailsResponseListener() { @Override public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && skuDetailsList != null) { for (SkuDetails skuDetails : skuDetailsList) { skuDetailsHashMap.put(skuDetails.getSku(), skuDetails); } if (IAPHelperListener != null) IAPHelperListener.onSkuListResponse(skuDetailsHashMap); } } }); }
补充说明
因为你的三个商品都是非消耗品,建议额外增加已购商品校验逻辑:在onPurchasehistoryResponse回调中将用户已购买的SKU存到本地集合,点击购买按钮时先判断是否已购买,已购买直接提示用户即可,不需要再拉起支付流程。
内容的提问来源于stack exchange,提问作者pearmak
相关产品推荐
相关产品推荐

