24

I'm testing in-app purchase using the three reserved product IDs for testing static Google Play Billing responses:

  • android.test.purchased
  • android.test.canceled
  • android.test.item_unavailable

However, setSku and setType seem to be deprecated in the BillingFlowParams.Builder class. Instead, we should be using setSkuDetails(SkuDetails).

How should I change the BillingFlowParams in the example code to use SkuDetails for the test product IDs?

BillingFlowParams flowParams = BillingFlowParams.newBuilder()
     .setSku(skuId)
     .setType(SkuType.INAPP) 
     .build();
int responseCode = mBillingClient.launchBillingFlow(flowParams);
Ping
  • 361
  • 1
  • 2
  • 5
  • Both the question and answers are outDated. BillingFlowParams is not used directly, and instead of returning responseCode, BillingResult is returned in response now. The latest answer hence is quite close to the answer therefore. – Abhinav Saxena Jan 18 '22 at 05:11

2 Answers2

21

you should get SkuDetails from BillingClient.querySkuDetailsAsync, the sample code may seems like this:

private BillingClient mBillingClient;

// ....

mBillingClient = BillingClient.newBuilder(this).setListener(new PurchasesUpdatedListener() {
    @Override
    public void onPurchasesUpdated(int responseCode, @Nullable List<Purchase> purchases) {
        if (responseCode == BillingClient.BillingResponse.OK
                && purchases != null) {

            // do something you want

        } else if (responseCode == BillingClient.BillingResponse.USER_CANCELED) {
        } else {
        }
    }
}).build();


mBillingClient.startConnection(new BillingClientStateListener() {
    @Override
    public void onBillingSetupFinished(@BillingClient.BillingResponse int billingResponseCode) {        

if (billingResponseCode == BillingClient.BillingResponse.OK) {
        // The billing client is ready. You can query purchases here.

List<String> skuList = new ArrayList<>();
        skuList.add("android.test.purchased");

SkuDetailsParams skuDetailsParams = SkuDetailsParams.newBuilder()
                    .setSkusList(skuList).setType(BillingClient.SkuType.INAPP).build();
mBillingClient.querySkuDetailsAsync(skuDetailsParams,
                    new SkuDetailsResponseListener() {
 @Override
  public void onSkuDetailsResponse(int responseCode, List<SkuDetails> skuDetailsList) {

  BillingFlowParams flowParams = BillingFlowParams.newBuilder()
                                    .setSkuDetails(skuDetailsList.get(0))
                                    .build();
  int billingResponseCode = billingClient.launchBillingFlow(SkuActivity.this, flowParams);
  if (billingResponseCode == BillingClient.BillingResponse.OK) {
                                // do something you want
                            }
                        }
                    });
                 }
               }


@Override
    public void onBillingServiceDisconnected() {
        // Try to restart the connection on the next request to
        // Google Play by calling the startConnection() method.
    }
});

You can also take a look to https://developer.android.com/google/play/billing/billing_library_overview

Stanojkovic
  • 1,612
  • 1
  • 17
  • 24
Renkuei
  • 276
  • 3
  • 8
  • 1
    @Ping, beware, google has update it's sample code. The code above MAY not work correctly, you should refer to the latest version. – Renkuei Oct 30 '18 at 00:25
  • 5
    @Renkuei +1 for the concise answer, however, the link you provided (at least by the time of posting this comment) also uses the deprecated setSku instead of the setSkuDetails, which I believe is the point of the whole question. – Gichamba Nov 10 '18 at 04:32
  • 2
    The example from Google mentioned (Link von Renkuei) still is not up to date. Could Google please check all examples when they are changing the library? – chksr May 26 '19 at 15:11
  • Quit correction in the code "enablePendingPurchases()." will be needed. – Hardy Jun 08 '19 at 14:09
  • 4
    don't forget to add `.enablePendingPurchases()` when building a `billingClient` instance – Kirill Karmazin Jun 24 '19 at 13:19
  • @KirillKarmazin is there anything special that's got to be implemented in order to support that `.enablePendingPurchases()` ? I haven't seen anything, so just checking... – Someone Somewhere Apr 09 '20 at 05:11
  • I guess `.enablePendingPurchases()` is not required for Subscriptions. Can anyone confirm? – Prince Aug 29 '20 at 09:08
  • I get the error: "Expected 2 parameters of types Int, (Mutable)List!" at the SkuDetailsResponseListener begin curly brackets. and SkuDetailsResponseListener() itself says: "Redundant SAM-constructor". I also tried the developer page, but withContext, Dispatchers, and querySkuDetails become "Unresolved References" – mystack Nov 14 '20 at 01:09
  • how to use getIntroductoryPrice() with this sample , help needed !!! – Tushar Pandey Jun 10 '21 at 04:31
1

I'm posting a step by step process for in-app billing, which I had tested recently after the release of Billing Library version 4.0

Google help resource can be found here

First things first: Update your build.gradle

dependencies {
    def billing_version = "4.0.0"

    implementation "com.android.billingclient:billing:$billing_version"
}

Now, comes the coding part: BillingActivity.java

private BillingClient mBillingClient;

// ...


submitButton.setOnClickListener(v -> {
    mBillingClient = BillingClient.newBuilder(this).enablePendingPurchases().setListener(new PurchasesUpdatedListener() {
        @Override
        public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
            if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK
                    && purchases != null) {
                for (Purchase purchase : purchases) {
                    handlePurchase(purchase);
                }
                // Perform your Successful Purchase Task here 
                
                Snackbar.make(findViewById(android.R.id.content), "Great!! Purchase Flow Successful! :)", Snackbar.LENGTH_LONG).show();
                dismiss();
            } else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) {
                // Handle an error caused by a user cancelling the purchase flow.
                Snackbar.make(findViewById(android.R.id.content), "User Cancelled the Purchase Flow!", Snackbar.LENGTH_LONG).show();
            } else {
                // Handle any other error codes.
                Snackbar.make(findViewById(android.R.id.content), "Error! Purchase Task was not performed!", Snackbar.LENGTH_LONG).show();
            }
        }
    }).build();

    mBillingClient.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.

                List<String> skuList = new ArrayList<>();
                skuList.add("billing_template_1");
                skuList.add("billing_template_2");
                SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
                params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
                mBillingClient.querySkuDetailsAsync(params.build(),
                        new SkuDetailsResponseListener() {
                            @Override
                            public void onSkuDetailsResponse(BillingResult billingResult,
                                                             List<SkuDetails> skuDetailsList) {
                                // Process the result.
                                // Retrieve a value for "skuDetails" by calling querySkuDetailsAsync().
                                BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
                                        .setSkuDetails(skuDetailsList.get(0))
                                        .build();
                                int responseCode = mBillingClient.launchBillingFlow(activity, billingFlowParams).getResponseCode();
                            }
                        });
            }
        }

        @Override
        public void onBillingServiceDisconnected() {
            // Try to restart the connection on the next request to Google Play by calling the startConnection() method.
            Toast.makeText(BillingActivity.this, "Service Disconnected!", Toast.LENGTH_SHORT).show();
        }
    });
});
        
void handlePurchase(Purchase purchase) {
    ConsumeParams consumeParams =
            ConsumeParams.newBuilder()
                    .setPurchaseToken(purchase.getPurchaseToken())
                    .build();

    ConsumeResponseListener listener = new ConsumeResponseListener() {
        @Override
        public void onConsumeResponse(BillingResult billingResult, @NonNull String purchaseToken) {
            if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                // Handle the success of the consume operation.
            }
        }
    };
    mBillingClient.consumeAsync(consumeParams, listener);
}
    
    
private void dismiss() {
        Intent intent = new Intent();
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        finish();
    }

FYI:

  • This is just an updated version to @Renkuei answer posted.
  • Don't forget .enablePendingPurchase()
  • Don't forget skuList.add("billing_template_1") which has to be done from your Developer Console. So, billing_template_1 is the name of your Monetise > Products > In-app products > Prouduct ID
Rohit Sharma
  • 1,271
  • 5
  • 19
  • 37