In-app billing workflow in a ListView

2019-02-14 19:01发布

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)

2条回答
趁早两清
2楼-- · 2019-02-14 19:42

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.

查看更多
贪生不怕死
3楼-- · 2019-02-14 19:50

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);

                    }
查看更多
登录 后发表回答