1

I'm testing my Android app and facing with the "Unable to buy item (response: 7:Item Already Owned)". The item is a "Managed In-app Product" type. I did some research and found this (http://developer.android.com/google/play/billing/api.html#managed):

Managed in-app products are items that have their ownership information tracked and managed
by Google Play. When a user purchases a managed in-app item, Google Play stores the
purchase information for each item on a per-user basis. This enables you to later query
Google Play at any time to restore the state of the items a specific user has purchased.
This information is persistent on the Google Play servers even if the user uninstalls the
application or if they change devices.

If you are using the Version 3 API, you can also consume managed items within your
application. You would typically implement consumption for items that can be purchased
multiple times (such as in-game currency, fuel, or magic spells). Once purchased, a managed
item cannot be purchased again until you consume the item, by sending a consumption request
to Google Play. To learn more about in-app product consumption, see Consuming Items.

...

You can use the consumption mechanism to track the user's ownership of in-app products.

In Version 3, all in-app products are managed. This means that the user's ownership of all
in-app item purchases is maintained by Google Play, and your application can query the
user's purchase information when needed. When the user successfully purchases an in-app
product, that purchase is recorded in Google Play. Once an in-app product is purchased, it
is considered to be "owned". In-app products in the "owned" state cannot be purchased from
Google Play. You must send a consumption request for the "owned" in-app product before
Google Play makes it available for purchase again. Consuming the in-app product reverts it
to the "unowned" state, and discards the previous purchase data.

How can I "send a consumption request" in Codename One?

William
  • 281
  • 3
  • 9

2 Answers2

3

Assuming that you are using IabHelper.java provided by google in its android SDK. Following is the path:

Android_SDK\sdk\extras\google\play_billing\samples\TrivialDrive\src\com\example\android\trivialdrivesample\util

Below is code for initializing in-app billing, querying google play for user's purchase and consuming the purchase.

  1. Initializing In-app billing.

    /* base64EncodedPublicKey should be YOUR APPLICATION'S PUBLIC KEY
       (that you got from the Google Play developer console). 
    */
    IabHelper mHelper = new IabHelper(this, base64EncodedPublicKey);
    
    // Check whether in-app billing is supported or not.
    mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener()
    {
        @Override
        public void onIabSetupFinished(IabResult result)
        {
            if (result.isSuccess())
            {
                // In-app billing is supported. Now, queryInventoryAsync to whether user already purchased.
                ArrayList<String> productIDs = new ArrayList<String>();
                // ITEM_SKU -> Name of the billing item in google play developer console
                productIDs.add(ITEM_SKU);
                mHelper.queryInventoryAsync(true, productIDs, mReceivedInventoryListener);
            }
            else
            {
                // Billing not supported by the device
            }
        }
    });
    
  2. Query user's purchases

    mReceivedInventoryListener
            = new IabHelper.QueryInventoryFinishedListener()
    {
        public void onQueryInventoryFinished(IabResult result,
                                             Inventory inventory)
        {
            if (result.isSuccess())
            {
                // Will be true if already purchased
                boolean hasPurchase = inventory.hasPurchase(ITEM_SKU);
    
                // Here enable or disable your app features
                ...
    
                    /* How to consume the purchase */
    
                // First, get the Purchase from inventory
                Purchase purchase = inventory.getPurchase(ITEM_SKU);
    
                // Consume the purchase
                mHelper.consumeAsync(purchase, mConsumeFinishedListener);
    
            }
            else
            {
                // Failed to query google play for purchases.
            }
        }
    };
    
  3. Purchase consumed listener

    mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener()
    {
    
        @Override
        public void onConsumeFinished(Purchase purchase, IabResult result)
        {
            if (result.isSuccess())
            {
                // Purchase consumed.
            }
            else
            {
                // Purchase not consumed.
            }
        }
    };
    
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Faraz
  • 2,144
  • 1
  • 18
  • 28
1

Use the

Purchase.getInAppPurchase().wasPurchased(String sku)

If the item is a managed item and was already purchased it will return true

Chen
  • 3,760
  • 1
  • 17
  • 21
  • Chen, the item is a managed and consuming item. So it should be purchased multiple times. So the CodenameOne should has a method in order to consume the item purchased. See this from the Google: **You would typically implement consumption for items that can be purchased multiple times (such as in-game currency, fuel, or magic spells). Once purchased, a managed item cannot be purchased again until you consume the item, by sending a consumption request to Google Play.** – William Feb 18 '16 at 05:29
  • if the item is a consumable type, the implementation is doing the consume for you on the item upon purchase or upon loading – Chen Feb 18 '16 at 08:27
  • I just tested with latest build on my Nexus 5 and it doesn't work. The "Unable to buy item response: 7:Item Already Owned" error is still happened. In Google Play, how the CodenameOne knows a "Managed Product" item is consumable type or non-consumable type in order to do the consume automatically once it is bought. I think only the developer knows which their "Managed Product" items are consumable types and which their "Managed Product" items are non-consumable types, and for consumable items bought by users, the developers have to manually call "consume" for them. Please advice. – William Feb 18 '16 at 22:20
  • non consumable items should declare their sku to ends with "nonconsume" for example "item1_nonconsume" otherwise it is considered consumable – Chen Feb 19 '16 at 08:11
  • Yes, the item is consumable and its sku is "100coins". So, the CodenameOne implementation should call "consume" for it when purchased, right? but I don't know why the "Unable to buy item response: 7:Item Already Owned" error is still happened when I try to purchase that item at the second time. – William Feb 19 '16 at 08:59
  • yes, the implementation does call consumeAsync on a consumable items. try to look for an exception on the ddms or maybe something in the item declaration is wrong – Chen Feb 20 '16 at 09:53
  • what is ddms? That error message was sent via itemPurchaseError() function in the main class which implements the itemPurchaseError interface. The item is a "Managed Product" with SKU is 100coins (no ends with "nonconsume"). Anyway, let me upgrade my Nexus 5 with the latest Android OS and test the app again. – William Feb 22 '16 at 05:11