4

I implemented in-app billing in Android application, have like 6 product they are like coins the user will buy in order to buy items in my app. The setup and the testing for in-app works perfectly I read all google documents and did what they said but my problem is that my product are shown in a listView i called the function mHelper.launchPurchaseFlow according to the position in the list in the activity but the items are always consumed or owned here is my code:

IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
    public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
        Log.d(TAG, "Query inventory finished.");

        // Have we been disposed of in the meantime? If so, quit.
        if (mHelper == null) return;

        // Is it a failure?
        if (result.isFailure()) {
            complain("Failed to query inventory: " + result);
            return;
        }

        Log.d(TAG, "Query inventory was successful.");

        /*
         * Check for items we own. Notice that for each purchase, we check
         * the developer payload to see if it's correct! See
         * verifyDeveloperPayload().
         */

        // Do we have the 100 coins upgrade?
        Purchase hundrendCoin = inventory.getPurchase(SKU_hundred);
        if(hundrendCoin != null && verifyDeveloperPayload(hundrendCoin));
        {
            Log.d(TAG, "User have it ");
            mHelper.consumeAsync(inventory.getPurchase(SKU_hundred), mConsumeFinishedListener);
        }

        // Do we have the 225 coins upgrade?
        Purchase two_hundred_twenty_fiveCoin = inventory.getPurchase(SKU_two_hundred_twenty_five);
        if(two_hundred_twenty_fiveCoin != null && verifyDeveloperPayload(two_hundred_twenty_fiveCoin));
        {
            Log.d(TAG, "User have it ");
            mHelper.consumeAsync(inventory.getPurchase(SKU_two_hundred_twenty_five), mConsumeFinishedListener);
        }

        // Do we have the 350 coins upgrade?
        Purchase three_hundred_fiftyCoin = inventory.getPurchase(SKU_three_hundred_fifty);
        if(three_hundred_fiftyCoin != null && verifyDeveloperPayload(three_hundred_fiftyCoin));
        {
            Log.d(TAG, "User have it ");
            mHelper.consumeAsync(inventory.getPurchase(SKU_three_hundred_fifty), mConsumeFinishedListener);
        }

        // Do we have the 475 coins upgrade?
        Purchase four_hundred_seventy_fiveCoin = inventory.getPurchase(SKU_four_hundred_seventy_five);
        if(four_hundred_seventy_fiveCoin != null && verifyDeveloperPayload(four_hundred_seventy_fiveCoin));
        {
            Log.d(TAG, "User have it ");
            mHelper.consumeAsync(inventory.getPurchase(SKU_four_hundred_seventy_five), mConsumeFinishedListener);
        }

        // Do we have the 600 coins upgrade?
        Purchase six_hundredCoin = inventory.getPurchase(SKU_six_hundred);
        if(six_hundredCoin != null && verifyDeveloperPayload(six_hundredCoin));
        {
            Log.d(TAG, "User have it");
            mHelper.consumeAsync(inventory.getPurchase(SKU_six_hundred), mConsumeFinishedListener);
        }

        // Do we have the 1225 coins upgrade?
        Purchase one_thousand_two_hundred_twenty_fiveCoin = inventory.getPurchase(SKU_one_thousand_two_hundred_twenty_five);
        if(one_thousand_two_hundred_twenty_fiveCoin != null && verifyDeveloperPayload(one_thousand_two_hundred_twenty_fiveCoin));
        {
            Log.d(TAG, "User have it ");
            mHelper.consumeAsync(inventory.getPurchase(SKU_one_thousand_two_hundred_twenty_five), mConsumeFinishedListener);
        }

        mHelper.flagEndAsync();

        Log.d(TAG, "Initial inventory query finished; enabling main UI.");
    }
};
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {

                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                    BankClass currentItem = BankList.get(position);
                    CoinItemID = currentItem.itemID;
                    if (currentItem.quantity == 100)
                    {
                        CoinItemID = currentItem.itemID;
                        String payload = "";
                        mHelper.launchPurchaseFlow(BankActivity.this, SKU_hundred, RC_REQUEST,
                                mPurchaseFinishedListener, payload);

                    } else if (currentItem.quantity == 225)
                    {
                        CoinItemID = currentItem.itemID;
                        String payload = "";
                        mHelper.launchPurchaseFlow(BankActivity.this, SKU_two_hundred_twenty_five, RC_REQUEST,
                                mPurchaseFinishedListener, payload);

                    } else if (currentItem.quantity == 350) {
                        CoinItemID = currentItem.itemID;
                        String payload = "";
                        mHelper.launchPurchaseFlow(BankActivity.this, SKU_three_hundred_fifty, RC_REQUEST,
                                mPurchaseFinishedListener, payload);
                    } else if (currentItem.quantity == 475) {
                        CoinItemID = currentItem.itemID;
                        String payload = "";
                        mHelper.launchPurchaseFlow(BankActivity.this, SKU_four_hundred_seventy_five, RC_REQUEST,
                                mPurchaseFinishedListener, payload);

                    } else if (currentItem.quantity == 600) {
                        CoinItemID = currentItem.itemID;
                        String payload = "";
                        mHelper.launchPurchaseFlow(BankActivity.this, SKU_six_hundred, RC_REQUEST,
                                mPurchaseFinishedListener, payload);

                    } else if (currentItem.quantity == 1225) {
                        CoinItemID = currentItem.itemID;
                        String payload = "";
                        mHelper.launchPurchaseFlow(BankActivity.this, SKU_one_thousand_two_hundred_twenty_five, RC_REQUEST,
                                mPurchaseFinishedListener, payload);

                    }
                }
            });
     @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
    if (mHelper == null) return;

    // Pass on the activity result to the helper for handling
    if (!mHelper.handleActivityResult(requestCode, resultCode, data))
    {
        // not handled, so handle it ourselves (here's where you'd
        // perform any handling of activity results not related to in-app
        // billing...
        super.onActivityResult(requestCode, resultCode, data);
    }
    else
    {
        Log.d(TAG, "onActivityResult handled by IABUtil.");
    }
}
boolean verifyDeveloperPayload(Purchase p)
{
    String payload = p.getDeveloperPayload();

    /*
     * TODO: verify that the developer payload of the purchase is correct. It will be
     * the same one that you sent when initiating the purchase.
     *
     * WARNING: Locally generating a random string when starting a purchase and
     * verifying it here might seem like a good approach, but this will fail in the
     * case where the user purchases an item on one device and then uses your app on
     * a different device, because on the other device you will not have access to the
     * random string you originally generated.
     *
     * So a good developer payload has these characteristics:
     *
     * 1. If two different users purchase an item, the payload is different between them,
     *    so that one user's purchase can't be replayed to another user.
     *
     * 2. The payload must be such that you can verify it even when the app wasn't the
     *    one who initiated the purchase flow (so that items purchased by the user on
     *    one device work on other devices owned by the user).
     *
     * Using your own server to store and verify developer payloads across app
     * installations is recommended.
     */

    return true;
}

// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener()
{
    public void onIabPurchaseFinished(IabResult result, Purchase purchase)
    {
        Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase);

        // if we were disposed of in the meantime, quit.
        if (mHelper == null) return;

        if (result.isFailure())
        {
            complain("Error purchasing: " + result);
            return;
        }
        if (!verifyDeveloperPayload(purchase)) {
            complain("Error purchasing. Authenticity verification failed.");
            return;
        }

        Log.d(TAG, "Purchase successful.");

        if (purchase.getSku().equals(SKU_hundred)) {
            // bought 1/4 tank of gas. So consume it.
            Log.d(TAG, "Purchase is 100 Coins. Starting consumption.");
            mHelper.consumeAsync(purchase, mConsumeFinishedListener);

        }
        else if (purchase.getSku().equals(SKU_two_hundred_twenty_five)) {
            Log.d(TAG, "Purchase is 225 Coins. Starting consumption.");
            mHelper.consumeAsync(purchase, mConsumeFinishedListener);

        }
        else if (purchase.getSku().equals(SKU_three_hundred_fifty)) {
            Log.d(TAG, "Purchase is 350 Coins. Starting consumption.");
            mHelper.consumeAsync(purchase, mConsumeFinishedListener);

        }
        else if (purchase.getSku().equals(SKU_four_hundred_seventy_five)) {
            Log.d(TAG, "Purchase is 475 Coins. Starting consumption.");
            mHelper.consumeAsync(purchase, mConsumeFinishedListener);

        }
        else if (purchase.getSku().equals(SKU_six_hundred)) {
            Log.d(TAG, "Purchase is 600 Coins. Starting consumption.");
            mHelper.consumeAsync(purchase, mConsumeFinishedListener);

        }
        else if (purchase.getSku().equals(SKU_one_thousand_two_hundred_twenty_five)) {
            Log.d(TAG, "Purchase is 1225 Coins. Starting consumption.");
            mHelper.consumeAsync(purchase, mConsumeFinishedListener);

        }

    }
};

// Called when consumption is complete
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
    public void onConsumeFinished(Purchase purchase, IabResult result) {
        Log.d(TAG, "Consumption finished. Purchase: " + purchase + ", result: " + result);

        // if we were disposed of in the meantime, quit.
        if (mHelper == null) return;

        // We know this is the "gas" sku because it's the only one we consume,
        // so we don't check which sku was consumed. If you have more than one
        // sku, you probably should check...
        if (result.isSuccess())
        {
            // successfully consumed, so we apply the effects of the item in our
            // game world's logic, which in our case means filling the gas tank a bit
            (new BuyCoinsTask()).execute();
            Log.d(TAG, "Consumption successful. Provisioning.");
        }
        else
        {
            complain("Error while consuming: " + result);
        }

        Log.d(TAG, "End consumption flow.");
    }
};

Any help would be appreciated.

Bank class:

public class BankClass
{
  public int itemID;
  public int quantity;
  public String price;
  public BankClass(int itemID,int quantity,String price)
  {
      this.itemID=itemID;
      this.quantity=quantity;
      this.price=price;
  }
}

Here is what i did with multi consuming .

List<Purchase> purchases = new ArrayList<>();
        purchases.add(inventory.getPurchase(SKU_hundred));
        purchases.add(inventory.getPurchase(SKU_two_hundred_twenty_five));
        purchases.add(inventory.getPurchase(SKU_three_hundred_fifty));
        purchases.add(inventory.getPurchase(SKU_four_hundred_seventy_five));
        purchases.add(inventory.getPurchase(SKU_six_hundred));
        purchases.add(inventory.getPurchase(SKU_one_thousand_two_hundred_twenty_five));

        IabHelper.OnConsumeMultiFinishedListener onCusumeListner = new IabHelper.OnConsumeMultiFinishedListener()
        {

            @Override
            public void onConsumeMultiFinished(List<Purchase> purchases, List<IabResult> results)
            {
                Log.d(TAG, "Consumption finished. Purchase: " + purchases + ", result: " + results);

                // if we were disposed of in the meantime, quit.
                if (mHelper == null) return;

                // We know this is the "gas" sku because it's the only one we consume,
                // so we don't check which sku was consumed. If you have more than one
                // sku, you probably should check...
                for(int i=0;i<results.size();i++)
                {
                    if (results.get(i).isSuccess())
                    {
                        // successfully consumed, so we apply the effects of the item in our
                        // game world's logic, which in our case means filling the gas tank a bit

                        Log.d(TAG, "Consumption successful. Provisioning.");
                    } else {
                        complain("Error while consuming: " + results);
                    }
                }
                Log.d(TAG, "End consumption flow.");
            }

        };
        mHelper.consumeAsync(purchases, onCusumeListner);

but in the result i don't know how to handle the success of the result for all items according to there position should i run a for loop for it or there is another way but still its crashing in all ways.

Logcat output:

 04-17 13:01:31.083    8312-8964/net.httpiamheroic.herioc    E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-3333
  Process: net.httpiamheroic.herioc, PID: 8312
java.lang.NullPointerException: Attempt to read from field   'java.lang.String   net.httpiamheroic.herioc.net.httpiamherioc.util.Purchase.mItemType' on a   null object reference
        at   net.httpiamheroic.herioc.net.httpiamherioc.util.IabHelper.consume(IabHelper.java:660)
        at net.httpiamheroic.herioc.net.httpiamherioc.util.IabHelper$3.run(IabHelper.java:953)
        at java.lang.Thread.run(Thread.java:818)
Vlad
  • 18,195
  • 4
  • 41
  • 71
Mostafa Addam
  • 6,956
  • 4
  • 20
  • 38

2 Answers2

4

Since you're consuming multiple items, would suggest to use consumeAsync for multiple items method by passing your list of purchases. You can find it inside TrivialDrive sample app for Iab ver 3

/**
 * Same as {@link consumeAsync}, but for multiple items at once.
 * @param purchases The list of PurchaseInfo objects representing the purchases to consume.
 * @param listener The listener to notify when the consumption operation finishes.
 */
public void consumeAsync(List<Purchase> purchases, OnConsumeMultiFinishedListener listener) {

Use onConsumeMultiFinished as your callback

public void onConsumeMultiFinished(List<Purchase> purchases, List<IabResult> results);

It should take care of sending proper async consume requests. Update you code and post any problems.

random
  • 10,238
  • 8
  • 57
  • 101
  • Sorry for the late reply @random your right but should i change my code from the inventory query each time to call consumeAsync and give it a list or at the end ill call it cause i'm checking each time if the user have it can you be more specific please how to use this in my code? – Mostafa Addam Apr 14 '15 at 12:10
  • you need to call consumeAsync once when the app starts and pass it your list of purchases and the method should take care of it – random Apr 15 '15 at 04:11
  • please can you check my edited answer please from what u suggested. – Mostafa Addam Apr 16 '15 at 14:00
  • Can you post your crash logs? Regarding handling the result, what do you want to do, you have a list of purchases and can check whether it is consumed by calling results.get(0).isSuccess() where the item's index is 0 - you may put inside a loop. – random Apr 17 '15 at 04:15
  • i edit my answer also today with what you suggested please can you take it a look if what I'm doing is correct or wrong whenever i start the activity it crashes with this new code and error @random – Mostafa Addam Apr 17 '15 at 10:07
  • I think the crash is because you initially did not set item type during purchase launchPurchaseFlow. So purchases received from inventory do not have that field set. Because of it consume method inside IabHelper reports a crash – random Apr 17 '15 at 13:47
  • so what should i do now in my case it won't be consumed because initially i set it in a wrong way is there a solution for that to start it from zero and how to set the item type before launching the purchaseFlow i'm really sorry for asking much but i really wanna know how it should work much appreciated from your side @random – Mostafa Addam Apr 17 '15 at 20:37
  • you may try to cancel them or comment the condition which checks for item type in IabHelper 's consume method temporarily till existing items are consumed. – random Apr 18 '15 at 07:10
1

change your class to these

public class BankClass {

    public int itemId;
    public int quantity;
    public String Price;

    public BankClass(int _itemId,int _quantity,String _Price){
        itemId = _itemId;
        quantity = _quantity;
        Price = _Price;
    }

    public int getItemId() {
        return itemId;
    }

    public String getPrice() {
        return Price;
    }

    public int getQuantity() {
        return quantity;
    }
}

in listitem click change these all code like bewlo

BankClass currentItem = BankList.get(position);
                    CoinItemID = currentItem.getItemId();
                    if (currentItem.getQuantity() == 100)
                    {
                        CoinItemID = currentItem.getItemId();
                        String payload = "";
                        mHelper.launchPurchaseFlow(BankActivity.this, SKU_hundred, RC_REQUEST,
                                mPurchaseFinishedListener, payload);

                    }
Dhaval Parmar
  • 18,812
  • 8
  • 82
  • 177
  • ok ill do that but the problem is in the beginning of the launch of the bank activity when i start IabHelper.QueryInventoryFinishedListener mGotInventoryListener it crashes immediately it say cannot start another async because the other one is not consumed yet and that i owned all the items @Dhawal Sodha Parmar – Mostafa Addam Apr 07 '15 at 11:50
  • make sure you are using letestversion of in app payment library try these solutions : http://stackoverflow.com/a/15757438 and http://stackoverflow.com/a/15582919 – Dhaval Parmar Apr 07 '15 at 11:57
  • i'm already using the same code that google provide in its sdk latest version and already saw those two links thats why i posted my code to check what i have done wrong in my workflow in this process am i missing something or doing it wrong in the setup ? – Mostafa Addam Apr 07 '15 at 12:00
  • it is the updated one because the question was asked 4 days ago my code before that was different after some researches i ended up with this code is the setup correct and the query correct in my code ? don't know why I'm always ended up with this error @Dhawal Sodha Parmar – Mostafa Addam Apr 07 '15 at 13:41