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

Google Play Billing V6集成报错DF-DFERH-01求助

Google Play Billing Library订阅唤起支付窗口出现DF-DFERH-01错误的解决方案

问题描述

我在Android Studio的Fragment中集成Google Play Billing Library实现订阅售卖功能,已在Google Play Console完成内部测试应用上传及订阅基础套餐配置,代码逻辑严格遵循文档步骤,能正常获取订阅产品信息,但唤起Google Play支付窗口时出现DF-DFERH-01错误。已尝试以下操作均未解决:

  • 清除Google Play商店与服务的缓存数据
  • 重启设备
  • 从内部测试渠道下载应用
  • 将Fragment替换为Activity
  • 降级库版本

其他带订阅功能的应用可正常唤起支付窗口,排除Google Play商店自身问题,附上相关代码:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    view = inflater.inflate(R.layout.fragment_sin_anuncios, container, false);
    PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
        @Override
        public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
            // To be implemented in a later section.
        }
    };

    billingClient = BillingClient.newBuilder(getContext())
            .setListener(purchasesUpdatedListener)
            .enablePendingPurchases()
            .build();

    connectToGooglePlayBilling();

    return view;
}

private void connectToGooglePlayBilling(){

    billingClient.startConnection(new BillingClientStateListener() {
        @Override
        public void onBillingSetupFinished(BillingResult billingResult) {

            if (billingResult.getResponseCode() ==  BillingClient.BillingResponseCode.OK) {
                // The BillingClient is ready. You can query purchases here.
                getProductDeatils();

            }

        }
        @Override
        public void onBillingServiceDisconnected() {
            // Try to restart the connection on the next request to
            // Google Play by calling the startConnection() method.
            Toast.makeText(getContext(), "No se pudo conectar a GooglePlay, revisa tu conexion a internet.\nIntentando conectarse nuevamente.", Toast.LENGTH_SHORT).show();
            connectToGooglePlayBilling();
            
        }
    });

}


private void getProductDeatils(){

    QueryProductDetailsParams queryProductDetailsParams =
            QueryProductDetailsParams.newBuilder()
                    .setProductList(
                            ImmutableList.of(
                                    QueryProductDetailsParams.Product.newBuilder()
                                            .setProductId("version_sin_anuncios")
                                            .setProductType(BillingClient.ProductType.SUBS)
                                            .build()))
                    .build();

    Activity activity = getActivity();

    billingClient.queryProductDetailsAsync(
            queryProductDetailsParams,
            new ProductDetailsResponseListener() {
                public void onProductDetailsResponse(BillingResult billingResult,
                                                     List<ProductDetails> productDetailsList) {
                    // check billingResult
                    // process returned productDetailsList

                    if(billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && productDetailsList != null){
                        TextView descripcion = view.findViewById(R.id.textViewSinAnuncios);
                        descripcion.setText(productDetailsList.get(0).getDescription());

                        Button BotonSinAnuncios = (Button) view.findViewById(R.id.buttonSinAnuncios);
                        BotonSinAnuncios.setOnClickListener(new View.OnClickListener()
                        {

                            @Override
                            public void onClick(View v)
                            {
                                Log.d("GoogleBillingService", "onBillingSetupFinished: billingResult: " + billingResult);
                                Log.d("GoogleBillingService", "Product detatils: " + productDetailsList.get(0));

                                ImmutableList productDetailsParamsList =
                                        ImmutableList.of(
                                                BillingFlowParams.ProductDetailsParams.newBuilder()
                                                        // retrieve a value for "productDetails" by calling queryProductDetailsAsync()
                                                        .setProductDetails(productDetailsList.get(0))
                                                        // to get an offer token, call ProductDetails.getSubscriptionOfferDetails()
                                                        // for a list of offers that are available to the user
                                                        .setOfferToken(String.valueOf(productDetailsList.get(0).getSubscriptionOfferDetails()))
                                                        .build()
                                        );


                                BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
                                        .setProductDetailsParamsList(productDetailsParamsList)
                                        .build();


                                // Launch the billing flow
                                billingClient.launchBillingFlow(activity, billingFlowParams);

                            }
                        });


                    }
                }
            }
    );

}

}

解决方案

1. 修复Offer Token获取逻辑(核心问题)

代码中setOfferToken的参数错误:String.valueOf(productDetailsList.get(0).getSubscriptionOfferDetails())是把整个List<SubscriptionOfferDetails>对象转成字符串,而非有效的优惠token。正确做法是从订阅方案列表中取出具体方案的token:

// 先判断方案列表不为空
List<ProductDetails.SubscriptionOfferDetails> offerDetails = productDetailsList.get(0).getSubscriptionOfferDetails();
if (offerDetails != null && !offerDetails.isEmpty()) {
    String validOfferToken = offerDetails.get(0).getOfferToken();
    // 使用该token构建参数
}

2. 完善空值判断逻辑

增加多层空值校验,避免异常同时确保参数有效性:

BotonSinAnuncios.setOnClickListener(new View.OnClickListener()
{
    @Override
    public void onClick(View v)
    {
        Log.d("GoogleBillingService", "onBillingSetupFinished: billingResult: " + billingResult);
        Log.d("GoogleBillingService", "Product details: " + productDetailsList.get(0));

        // 校验产品列表
        if (productDetailsList == null || productDetailsList.isEmpty()) {
            Toast.makeText(getContext(), "产品信息异常", Toast.LENGTH_SHORT).show();
            return;
        }
        ProductDetails productDetails = productDetailsList.get(0);
        
        // 校验订阅方案列表
        List<ProductDetails.SubscriptionOfferDetails> offerDetails = productDetails.getSubscriptionOfferDetails();
        if (offerDetails == null || offerDetails.isEmpty()) {
            Toast.makeText(getContext(), "无可用订阅方案", Toast.LENGTH_SHORT).show();
            return;
        }

        // 获取有效offer token
        String offerToken = offerDetails.get(0).getOfferToken();

        ImmutableList<BillingFlowParams.ProductDetailsParams> productDetailsParamsList =
                ImmutableList.of(
                        BillingFlowParams.ProductDetailsParams.newBuilder()
                                .setProductDetails(productDetails)
                                .setOfferToken(offerToken)
                                .build()
                );

        BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
                .setProductDetailsParamsList(productDetailsParamsList)
                .build();

        // 校验Activity有效性
        if (getActivity() == null) {
            return;
        }
        billingClient.launchBillingFlow(getActivity(), billingFlowParams);
    }
});

3. 优化BillingClient生命周期管理

在Fragment销毁时关闭BillingClient连接,避免内存泄漏:

@Override
public void onDestroy() {
    super.onDestroy();
    if (billingClient != null && billingClient.isReady()) {
        billingClient.endConnection();
    }
}

4. 验证测试账号与签名一致性

  • 确认测试账号已加入Google Play Console内部测试人员列表,且已接受测试邀请
  • 确保本地打包测试应用的签名文件,与Google Play Console上传应用的签名完全一致

内容的提问来源于stack exchange,提问作者Jorge Barajas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 23:01:36