You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android应用内支付(IAB)多SKU购买提示SKU为空的代码修复咨询

问题原因

你遇到的the SKU cannot be null报错是因为调用launchBillingFlow时传入的SkuDetails对象为空,核心原因有三个:

  1. 商品详情查询失败/返回不全时,直接覆盖了本地保存的商品详情Map,导致已有的商品信息丢失
  2. BillingClient服务断开后没有自动重连逻辑,后续的商品详情查询直接失败返回空
  3. 点击按钮时只判断了商品Map是否为空,没有判断目标SKU是否存在于Map中,直接调用get方法返回空值

修复方案

一、修改Activity类代码

  1. 调整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);
    }
}
  1. 调整onSkuListResponse方法,改为合并新拉取的商品信息而不是直接覆盖,避免查询失败清空原有数据
@Override
public void onSkuListResponse(HashMap<String, SkuDetails> newSkuDetails) {
    if (newSkuDetails != null && !newSkuDetails.isEmpty()) {
        skuDetailsHashMap.putAll(newSkuDetails);
    }
}

二、修改IabHelper类代码

  1. 给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");
    }
}
  1. 补全服务断开后的自动重连逻辑
@Override
public void onBillingServiceDisconnected() {
    Log.d(TAG, "onBillingServiceDisconnected: try to reconnect");
    // 延迟1秒重连,避免频繁请求
    new Handler(Looper.getMainLooper()).postDelayed(() -> {
        if (mBillingClient != null && !mBillingClient.isReady()) {
            startConnection();
        }
    }, 1000);
}
  1. 给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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 08:57:02