Question

I'm trying to implement the inApp billing service with IabHelper. I manage to go through the full purchase process without problems.

//-----------------------------------------------
public void billingServiceLaunchPurchase(String item) {
//-----------------------------------------------
    if (isNetworkAvailableSync(getBaseContext())) {
        currBuyItem=item;
        billingConsummeType=1;
        mHelper.launchPurchaseFlow(BaseActivity.this, item, 10001, mPurchaseFinishedListener, "");
    }
    else {
        onBillingServiceFailed();  
    }
}

    //-----------------------------------------------
    mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
    //-----------------------------------------------
        public void onIabPurchaseFinished(IabResult result, Purchase purchase) 
        {
           if (result.isFailure()) {
              // Handle error
              onBillingServiceFailed();                
              return;
         }      
         else if (purchase.getSku().equals(currBuyItem)) {
             billingServiceConsumeItem();
         }

        }
    }; 

@Override
//-----------------------------------------------------------------------    
protected void onActivityResult(int requestCode, int resultCode, Intent data)
//-----------------------------------------------------------------------
{
    if (billingServiceConnected) {
          if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {     
              super.onActivityResult(requestCode, resultCode, data);
          }
          else {
              // onActivityResult handled by IABUtil.
          }
    }
    else
           super.onActivityResult(requestCode, resultCode, data);

}    

However, I cannot detect the event when the user launches the purchase but then press the backspace on the Google confirmation screen with the button "BUY" to interrupt it.

It neither triggers a failure on onIabPurchaseFinished nor it triggers onActivityResult so my application stays in an intermediary status.

Please help me to solve my problem.

Was it helpful?

Solution

According to what I have understood your question, you are searching for purchase cancel event in app billing.

You can trigger this via onActivityResult() method.Put below code in onActivityResult() method. There is simple RESEULT_CANCEL type that shows you user has been cancel purchasing.

    if (mHelper == null)
                return;

            if (requestCode == 10001) {

                int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
                String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
                Log.d("INAPP_PURCHASE_DATA", ">>>" + purchaseData);
                String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
                Log.d("INAPP_DATA_SIGNATURE", ">>>" + dataSignature);
                String continuationToken = data
                        .getStringExtra("INAPP_CONTINUATION_TOKEN");
                Log.d("INAPP_CONTINUATION_TOKEN", ">>>" + continuationToken);

                if (resultCode == RESULT_OK) {
                    try {
                        Log.d("purchaseData", ">>>"+purchaseData);
                        JSONObject jo = new JSONObject(purchaseData);
                        String sku = jo.getString("productId");
                        alert("You have bought the " + sku
                                + ". Excellent choice, adventurer!");
                    } catch (JSONException e) {
                        alert("Failed to parse purchase data.");
                        e.printStackTrace();
                    }
                } else if (resultCode == RESULT_CANCELED) {

                    Toast.makeText(AppMainTest.this,
                            "Sorry, you have canceled purchase Subscription.",
                            Toast.LENGTH_SHORT).show();

                } else if (resultCode == IabHelper.BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED) {
                    Toast.makeText(AppMainTest.this, "Item already owned",
                            Toast.LENGTH_SHORT).show();
                }

            }
}

or

you can also handle manually by using your business logic. check if user cancel purchase product then put flag user has been purchased or not if not then call launchPurchaseFlow() method again.

EDIT

onDestroy() method 

@Override
    public void onDestroy() {
        super.onDestroy();

        // very important:
        Log.d(TAG, "Destroying helper.");
        if (mHelper != null)
            mHelper.dispose();
        mHelper = null;
    }

if you have button then you can directly call launchPurchaseFlow() method into onClick event so that every time your mHelper created as new purchase.

or

if you are using it in onCreate method and you haven't any button click event to purchase product then you have to give value as null according to my knowledge.

Hope it will solve your problem.

OTHER TIPS

When user press BACK or press outside the dialog, the purchase flow is still in process and if user press PURCHASE button again, there will be an exception "Can't start async operation because another async operation is in progress".

To fix this, I had manually create a flag to know if there is a purchase flow in progress. And since IABHelper don't provide a way to dispose a purchase flow, I have to dispose mHelper and recall initBilling()

boolean onPurchaseFlow = false; 
public void purchaseItem() {
        if (!onPurchaseFlow) {
            mHelper.launchPurchaseFlow(mActivity, SKU_PREMIUM, RC_REQUEST, mPurchaseFinishedListener, "");
            onPurchaseFlow = true;
        } else {
    //dispose mHelper       
    if (mHelper != null) {
            mHelper.dispose();
            mHelper = null;
            }

            initBilling(mActivity); // restart IABHelper, a code snippet will fire launchPurchaseFlow when onPurchaseFlow is true
        }
        }

The other important part is call launchPurchaseFlow in onQueryInventoryFinished() to ensure that it is called (in the second request of user) when all the init operation has completed:

public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
        // YOUR CODE HERE
        if (onPurchaseFlow == true) {
        mHelper.launchPurchaseFlow(mActivity, SKU_PREMIUM, RC_REQUEST, mPurchaseFinishedListener, "");
        }
    }

Remember to reset the flag onPurchaseFlow = false when finish in onIabPurchaseFinished()

    public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
            Log.d(TAG, "Purchase successful.");

            if (purchase.getSku().equals(SKU_PREMIUM)) {
            // bought the premium upgrade!
            // YOUR CODE HERE
            onPurchaseFlow = false;
        }
}

You can access the result code through IabResult class, and compare it with the different result codes in IabHelper class, and use it in your OnIabPurchaseFinishedListener:

    IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener
        = new IabHelper.OnIabPurchaseFinishedListener() {
    public void onIabPurchaseFinished(IabResult result, Purchase purchase)
    {            

        if (result.isFailure()) {

            if (result.getResponse() == IabHelper.BILLING_RESPONSE_RESULT_USER_CANCELED  || result.getResponse() == IabHelper.IABHELPER_USER_CANCELLED){

                // user cancelled purchase

            } else {

            // any oder reasult

            }
            return;
        }

        else if (purchase.getSku().equals(SKU_SPIRIT_LEVEL)) {

            // no error, purchase succeeded                

        }
    }
};

you can detect the back press overriding by this method

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK)) {
//do what you want to avoid going back while during transaction
Log.d("bak button pressed", "ture");
}
return super.onKeyDown(keyCode, event);
}

even check this out, it might help you

Check if back key was pressed in android?

Inside IabHelper there's a method called handleActivityResult(...).

If you override onActivityResult (Fragment or Activity) and call that method inside (call it with the same parameters). In this way, the helper manage all the callbacks and can redo the purchase flow without launching any exceptions.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top