简体   繁体   中英

Android App crashing on click of in-app purchase

I referred to the Android documentation to implement an in-app purchase to remove ads. https://developer.android.com/google/play/billing/integrate

This is my code:

public static final String AD_REMOVAL_SKU = "remove_ads";

private void LoadBillingInfo() {
        PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
            @Override
            public void onPurchasesUpdated(@NonNull BillingResult billingResult, List<Purchase> purchases) {
                // To be implemented in a later section.
                if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) {
                    for (Purchase purchase : purchases) {
                        if (purchase.getSku().equals(AD_REMOVAL_SKU)) {
                            //Acknowledge the payment
                            AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = new AcknowledgePurchaseResponseListener() {
                                @Override
                                public void onAcknowledgePurchaseResponse(@NonNull BillingResult billingResult) {
                                    if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                                        areAdsRemoved = true;
                                        sharedPreferences.edit().putBoolean(AD_REMOVAL_SKU, areAdsRemoved).apply();
                                        DestroyBannerAd();
                                        Log.i("LOG", "Congrats! You are Ad free!");
                                        Toast.makeText(MainActivity.this, "Congrats! You are Ad free!", Toast.LENGTH_SHORT).show();
                                    }
                                }
                            };
                            if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
                                if (!purchase.isAcknowledged()) {
                                    AcknowledgePurchaseParams acknowledgePurchaseParams =
                                            AcknowledgePurchaseParams.newBuilder()
                                                    .setPurchaseToken(purchase.getPurchaseToken())
                                                    .build();
                                    billingClient.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
                                }
                            }
                        }
                    }
                }
            }
        };

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

        StartBillingConnection();
    }

private void StartBillingConnection() {
        billingClient.startConnection(new BillingClientStateListener() {
            @Override
            public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
                if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                    // The BillingClient is ready. You can query purchases here.
                    if (HasNetwork()) {
                        isBillingClientReady = true;
                        Toast.makeText(MainActivity.this, "onBillingSetupFinished", Toast.LENGTH_SHORT).show();
                        Log.i("LOG", "onBillingSetupFinished");
                        Log.i("LOG", "Response code: " + billingResult.getResponseCode());
                    }
                }
            }

            @Override
            public void onBillingServiceDisconnected() {
                // Try to restart the connection on the next request to
                // Google Play by calling the startConnection() method.
                isBillingClientReady = false;
                Toast.makeText(MainActivity.this, "onBillingServiceDisconnected", Toast.LENGTH_SHORT).show();
                Log.i("LOG", "onBillingServiceDisconnected");
                if (HasNetwork()) {
                    StartBillingConnection();
                }
            }
        });
    }

    private void MakePayment() {
        final SkuDetails[] skuDetail = new SkuDetails[1];
        Log.i("LOG", "1");
        List<String> skuList = new ArrayList<>();
        Log.i("LOG", "2");
        skuList.add(AD_REMOVAL_SKU);
        Log.i("LOG", "3");
        SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
        Log.i("LOG", "4");
        params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
        Log.i("LOG", "5");
        billingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() {
            @Override
            public void onSkuDetailsResponse(@NonNull BillingResult billingResult, List<SkuDetails> skuDetailsList) {
                Log.i("LOG", "6");
                // Process the result.
                if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK
                        && skuDetailsList != null) {
                    Log.i("LOG", "7");
                    for (Object skuDetailsObject : skuDetailsList) {
                        Log.i("LOG", "8");
                        SkuDetails skuDetails = (SkuDetails) skuDetailsObject;
                        Log.i("LOG", "9");
                        String sku = skuDetails.getSku();
                        Log.i("LOG", "10");
                        if (AD_REMOVAL_SKU.equals(sku)) {
                            Toast.makeText(MainActivity.this, "Right Inside", Toast.LENGTH_SHORT).show();
                            Log.i("LOG", "Right Inside");
                            skuDetail[0] = skuDetails;
                        }
                    }
                }
            }
        });

        Toast.makeText(this, skuDetail[0].getSku() + " " + skuDetail[0].getTitle(), Toast.LENGTH_LONG).show();
        Log.i("LOG", skuDetail[0].getSku() + " " + skuDetail[0].getTitle());

// Retrieve a value for "skuDetails" by calling querySkuDetailsAsync().
        BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
                .setSkuDetails(skuDetail[0])
                .build();
        billingClient.launchBillingFlow(this, billingFlowParams);
    }

I call this onClick:

if (!areAdsRemoved) {
                    if (isBillingClientReady) {
                        MakePayment();
                    } else {
                        Log.i("LOG", "Sorry! You are unable to make the payment due to network connectivity issues");
                        Toast.makeText(this,
                                "Sorry! You are unable to make the payment due to network connectivity issues",
                                Toast.LENGTH_LONG).show();
                        LoadBillingInfo();
                    }
                }

But, when I click the button to remove ads, the app crashes.
So, I put Log statements everywhere. And I found out that Log.i("LOG", "5"); is the last printed Log statement.

When the app crashes I get this error:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String b.a.a.a.j.a()' on a null object reference
        at b.d.b.b.a0.a.a(:17)
        at a.b.o.i.g.e()
        at a.b.o.i.g.s(:1)
        at b.d.b.b.z.h$a.onClick()
        at android.view.View.performClick(View.java:5637)
        at android.view.View$PerformClick.run(View.java:22433)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6126)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

I am unable to find a solution for this problem...
Has anyone faced this issue? Please Help!

skuDetail[0] is null. Move the code that dereferences it to the async callback where that data is available

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM