Android Studio - 应用内购买:计费客户端问题

问题描述 投票:0回答:1

几年前,我制作了一个Android应用程序,但该项目被错误删除了。几年后,我决定再写一次。所以我已经到了我想添加应用程序购买(删除广告)的部分,但不知何故它没有按计划工作。我尝试按照文档并在线搜索,但没有成功。

我的应用程序 build.gradle 中有这些:

dependencies {

    implementation("androidx.appcompat:appcompat:1.6.1")
    implementation("com.google.android.material:material:1.10.0")
    implementation("androidx.constraintlayout:constraintlayout:2.1.4")
    implementation("androidx.test.espresso:espresso-core:3.5.1")

    val billing_version = "6.1.0"

    implementation("com.android.billingclient:billing:$billing_version")
    implementation("com.android.billingclient:billing-ktx:$billing_version")

    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.5")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}

这就是我的 Java 类的样子:

import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.BillingClientStateListener;
import com.android.billingclient.api.BillingFlowParams;
import com.android.billingclient.api.BillingResult;
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.PurchasesUpdatedListener;
import com.android.billingclient.api.SkuDetails;
import com.android.billingclient.api.SkuDetailsParams;

import java.util.Arrays;
import java.util.List;
import java.util.Locale;

public class InfoController extends AppCompatActivity implements PurchasesUpdatedListener {

    private Button upgradeButton;

    // Billing variables
    private BillingClient billingClient;
    private PurchasesUpdatedListener purchasesUpdatedListener;

    private SkuDetails myProductSkuDetails; // Define SkuDetails field

    List<String> skuList = Arrays.asList("com.xxxxxxx.yyyyyyyyyyyyy.pro");


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_info);

        upgradeButton = findViewById(R.id.upgradeButton);

        billingClient = BillingClient.newBuilder(this)
                .setListener(this)
                .enablePendingPurchases()
                .build();

        billingClient.startConnection(new BillingClientStateListener() {
            @Override
            public void onBillingSetupFinished(BillingResult billingResult) {
                if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                    // The billing client is ready, query SkuDetails here
                    querySkuDetails();
                } else {
                    // Handle the error
                    Toast.makeText(InfoController.this, "Billing setup failed: " + billingResult.getDebugMessage(), Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onBillingServiceDisconnected() {
                // Handle the case when the billing service is disconnected
                Toast.makeText(InfoController.this, "Billing service disconnected", Toast.LENGTH_SHORT).show();
            }
        });

    }

    private void querySkuDetails() {
        // Query SkuDetails for your product
        List<String> skuList = Arrays.asList("com.xxxxxxx.yyyyyyyyyyyyy.pro");
        SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
        params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);

        Log.d("BillingDebug", "Before querySkuDetailsAsync");
        billingClient.querySkuDetailsAsync(params.build(), (billingResult, skuDetailsList) -> {
            Log.d("BillingDebug", "Inside querySkuDetailsAsync callback");
            if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && skuDetailsList != null) {
                // Use the first SkuDetails object
                Toast.makeText(this, "Billing OK", Toast.LENGTH_SHORT).show();
                myProductSkuDetails = skuDetailsList.get(0);
            } else {
                Toast.makeText(this, "Failed to retrieve SKU details", Toast.LENGTH_SHORT).show();
            }
        });
        Log.d("BillingDebug", "After querySkuDetailsAsync");

    }

    @Override
    public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
        // Implement your logic here when purchases are updated
        if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) {
            for (Purchase purchase : purchases) {
                // Handle the purchase
                Toast.makeText(this, "OK", Toast.LENGTH_SHORT).show();
            }
        } else {
            // Handle an error
            Toast.makeText(this, "ERROR", Toast.LENGTH_SHORT).show();
        }
    }

    public void onUpgradeButtonClick(View view) {
        if (myProductSkuDetails != null) {
            Toast.makeText(this, "Not null", Toast.LENGTH_SHORT).show();
            // Create a BillingFlowParams object
            BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
                    .setSkuDetails(myProductSkuDetails)
                    .build();

            // Launch the billing flow
            BillingResult result = billingClient.launchBillingFlow(this, billingFlowParams);
            if (result.getResponseCode() != BillingClient.BillingResponseCode.OK) {
                // Handle the error


            }
        } else {
            // SkuDetails not available, handle accordingly

            Toast.makeText(this, "SkuDetails not available", Toast.LENGTH_SHORT).show();
        }
    }

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

问题:

因此,当我加载此活动时,它打开正常,没有错误,也没有 Toast 消息。但是当我按

onUpgradeButtonClick
时,它会给我 Toast 消息:
SkuDetails not available

我在支持 Google Play 商店的模拟器 Pixel 7 API 34 上运行此程序,并且我已登录到 Google Play 商店。

有什么建议吗?

android android-studio in-app-billing android-billing google-play-billing
1个回答
0
投票

根据官方 google-in-app-billing 文档,您应该

  • SkuDetailsParams
    替换为
    QueryProductDetailsParams
  • 切换
    BillingClient.querySkuDetailsAsync()
    呼叫以使用
    BillingClient.queryProductDetailsAsync()

更新

querySkuDetails()
功能

 private void querySkuDetails() {
    // QueryProductDetailsParams for your product
    QueryProductDetailsParams.Product inAppProduct = QueryProductDetailsParams.Product.newBuilder()
            .setProductId("com.xxxxxxx.yyyyyyyyyyyyy.pro")
            .setProductType(BillingClient.ProductType.INAPP)
            .build();
    List<QueryProductDetailsParams.Product> productList = Arrays.asList(inAppProduct);
    QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder()
            .setProductList(productList)
            .build();
    billingClient.queryProductDetailsAsync(params, (billingResult, productDetailsList) -> {
        // productDetailsList will be List<ProductDetails>
        if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && !productDetailsList.isEmpty()) {
            // Use the first productDetailsList object
            Toast.makeText(this, "Billing OK", Toast.LENGTH_SHORT).show();
            myProductSkuDetails = productDetailsList.get(0);
        } else {
            Toast.makeText(this, "Failed to retrieve SKU details", Toast.LENGTH_SHORT).show();
        }
    });
}

更新

queryProductDetailsAsync
后,您的
myProductSkuDetails
对象将更改为
ProductDetails

 private ProductDetails myProductSkuDetails; // Define SkuDetails field

请参阅 integrate-google-in-app-billingMigration-to-goggle-play-billing-v6 官方文档了解详细信息。

© www.soinside.com 2019 - 2024. All rights reserved.