Android订阅功能实现遇阻:旧API废弃适配求助
Google Play Billing API 废弃接口适配方案(订阅场景)
针对你遇到的旧版BillingClient API(如querySkuDetailsAsync、SkuDetailsParams)废弃问题,以下是基于最新BillingClient v6+的适配代码,完全匹配你的订阅页流程需求:
1. 依赖更新
确保使用最新稳定版Billing库:
dependencies { implementation 'com.android.billingclient:billing:6.0.1' // 可替换为当前最新稳定版 }
2. BillingClient 初始化
替换旧版初始化逻辑,适配新的连接回调:
private BillingClient billingClient; private void initBillingClient() { billingClient = BillingClient.newBuilder(this) .setListener(this::onPurchaseUpdate) .enablePendingPurchases() .build(); billingClient.startConnection(new BillingClientStateListener() { @Override public void onBillingSetupFinished(@NonNull BillingResult billingResult) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { // 连接成功,立即查询5个订阅计划 querySubscriptionProducts(); } } @Override public void onBillingServiceDisconnected() { // 连接断开自动重试 billingClient.startConnection(this); } }); }
3. 查询订阅商品(替代废弃的querySkuDetailsAsync)
用ProductDetailsParams和queryProductDetailsAsync替换旧接口:
private void querySubscriptionProducts() { // 替换为你在Google Play Console配置的5个订阅productId List<String> subscriptionIds = Arrays.asList( "sub_monthly_basic", "sub_monthly_pro", "sub_yearly_basic", "sub_yearly_pro", "sub_lifetime" ); ProductDetailsParams params = ProductDetailsParams.newBuilder() .setProductList( subscriptionIds.stream() .map(id -> Product.newBuilder() .setProductId(id) .setProductType(BillingClient.ProductType.SUBS) .build()) .collect(Collectors.toList()) ) .build(); billingClient.queryProductDetailsAsync(params, (billingResult, productDetailsList) -> { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && productDetailsList != null) { // 获取到订阅详情,更新UI展示5个计划 renderSubscriptionPlans(productDetailsList); } }); }
4. 发起订阅支付(适配新版launchBillingFlow)
基于ProductDetails中的订阅优惠信息创建支付请求:
private void startSubscriptionPurchase(ProductDetails productDetails) { // 获取订阅优惠(如免费试用、首月折扣),这里默认取第一个优惠 List<ProductDetails.SubscriptionOfferDetails> offerDetails = productDetails.getSubscriptionOfferDetails(); if (offerDetails == null || offerDetails.isEmpty()) return; ProductDetails.SubscriptionOfferDetails selectedOffer = offerDetails.get(0); BillingFlowParams flowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList( Collections.singletonList( BillingFlowParams.ProductDetailsParams.newBuilder() .setProductDetails(productDetails) .setOfferToken(selectedOffer.getOfferToken()) .build() ) ) .build(); billingClient.launchBillingFlow(this, flowParams); }
5. 支付结果处理与页面跳转
处理支付成功、取消、待支付等场景,验证后跳转到主界面:
private void onPurchaseUpdate(BillingResult billingResult, @Nullable List<Purchase> purchases) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) { for (Purchase purchase : purchases) { handleValidPurchase(purchase); } } else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) { // 用户取消支付,可留在订阅页或提示 } } private void handleValidPurchase(Purchase purchase) { if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { if (!purchase.isAcknowledged()) { // 确认购买(必须调用,否则Google会退款) AcknowledgePurchaseParams acknowledgeParams = AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build(); billingClient.acknowledgePurchase(acknowledgeParams, result -> { if (result.getResponseCode() == BillingClient.BillingResponseCode.OK) { // 确认成功,跳转到主界面 startActivity(new Intent(SubscriptionActivity.this, MainActivity.class)); finish(); } }); } else { // 已确认过的购买,直接跳转 startActivity(new Intent(SubscriptionActivity.this, MainActivity.class)); finish(); } } else if (purchase.getPurchaseState() == Purchase.PurchaseState.PENDING) { // 待处理支付(如运营商代扣),可提示用户等待后续结果 } }
关键注意事项
- 所有
productId必须与Google Play Console中配置的订阅ID完全一致 - 必须做服务器端购买验证,本地验证仅作临时处理,不能作为最终凭证
- 若有多个订阅优惠(如不同时长、折扣),可通过
offerToken筛选指定优惠 - 记得在
onDestroy中关闭BillingClient连接:billingClient.endConnection();
内容的提问来源于stack exchange,提问作者jesus vallad
相关产品推荐
相关产品推荐

