Search Unity

[Solved] Query owned products

Discussion in 'Unity IAP' started by pep_dj, Sep 5, 2016.

Thread Status:
Not open for further replies.
  1. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
  2. ap-unity

    ap-unity

    Unity Technologies

    Joined:
    Aug 3, 2016
    Posts:
    1,519
    Hi @pep_dj,

    hasReceipt is a transient field. It is only accurate in the current session when the purchase was made or restored.

    The best way to confirm a purchase is to parse the receipt. As mentioned in the thread you linked to, Apple stores provide a single unified receipt containing the current state of ownership of all products the user owns. After that, you can keep a local storage of what the user owns.

    I'm curious about your use case for finding products that are owned? If you are trying to implement a feature that restores purchases after a user reinstalls your app, then we have an established process for that.
    https://docs.unity3d.com/Manual/UnityIAPRestoringTransactions.html
     
  3. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    Thanks for your answer.

    What I want is to manage refunds.

    In my Android apps, I call "queryInventoryAsync" method each time the user opens the app, so I update owned products in my local storage each time the app starts. If want to know if a purchase has been refunded, so I can update my local storage.
    Also, the Android docs says this is a good practice: https://developer.android.com/training/in-app-billing/purchase-iab-products.html#QueryPurchases

    I would like to do the same in my Unity games. Is this possible?
     
  4. erika_d

    erika_d

    Joined:
    Jan 20, 2016
    Posts:
    413
    Hi @pep_dj,

    Currently queryInventoryAsync is called by Unity IAP on Initialization, and in the FetchAdditionalProducts method. I did some googling, and am unclear how queryInventoryAsync manages refunds though...if you have any documentation on it could you link it to me? Thanks!

    Apple handles refunds by adding information to a field in their receipt, which Unity IAP doesn't handle right now. You will need to manually parse the receipts Apple returns (and Unity IAP passes on) for the cancellation_date field, which is the one Apple uses to indicate if a refund has been given. Here are some pages that may prove useful:
    https://developer.apple.com/library.../apple_ref/doc/uid/DTS40016228-CH1-RECEIPTURL
    https://forums.developer.apple.com/thread/46737
    https://developer.apple.com/library...teAppStoreReceipt/Chapters/ReceiptFields.html
    https://docs.unity3d.com/Manual/UnityIAPiOSMAS.html

    I hope that helps!
     
  5. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    Thanks @erika_d :)

    About Apple: we will try to read and parse app receipt, thanks :)

    About Android:

    This is how queryInventoryAsync manages refunds: after it's called, a callback is executed, and I receive a "Inventory" object, so it's like:

    Code (CSharp):
    1. public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
    2.     if (result.isSuccess()){
    3.         myProduct.owned = inventory.hasPurchase("my_product_sku");
    4.     }
    5. }
    So, if inventory.hasPurchase returns false, then the product has not been purchased, or it has been refunded.

    Here is an example of how Google uses it: https://github.com/googlesamples/an.../android/trivialdrivesample/MainActivity.java

    So, in Android, we use the same method (queryInventoryAsync) for restore purchases, and handle refunds, because we update the local inventory each time the app starts.

    If hasReceipt is a transient field, how can we keep our local inventory updated in Unity?
     
  6. erika_d

    erika_d

    Joined:
    Jan 20, 2016
    Posts:
    413
    Hi @pep_dj

    Ok so based on your information we took another look at the hasReceipt field, and it turns out our understanding was a little off. hasReceipt is transient on Apple, but should in fact not be transient on google play. When we call queryInventoryAsync and get the data from Google, we do in fact use it to populate the hasReceipt field, which you should then be able to use to keep you local inventory up to date. My apologies for our bad information earlier, we are working on building out the documentation to better reflect this information.
     
  7. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    Thanks for the information. Now it's clear how to handle refunds in Android and iOS ;)
     
    erika_d likes this.
  8. mrm83

    mrm83

    Joined:
    Nov 29, 2014
    Posts:
    345
    The first link states that "Important: cancellation_date is not currently added for consumable and non-renewing subscription products."

    So does that mean it is not possible to handle refunds for consumables?
     
  9. mrm83

    mrm83

    Joined:
    Nov 29, 2014
    Posts:
    345
    Anyone?
     
  10. Keepabee

    Keepabee

    Joined:
    Jul 12, 2012
    Posts:
    58
    From what I've understood in this thread so far: Unity IAP / UnityPurchasing does NOT handle local inventory, and is NOT aware of if you have or have not purchased a Non-Consumable Item (something like a vanity character decoration IAP or Coin Doubler IAP).

    Instead, game developers have to build their own systems to store successful purchases locally (PlayerPrefs or save files) or online (program your own server backend, purchase a hosting deal, install and setup your database, setup connection in game and check from your server via some API).

    Having read Unity IAP/Unity Purchasing manual a couple of times and spent at least a week extra before getting this to work, Unity IAP/Unity Purchasing folks could maybe make it a little clearer that this is what is expected of the user. This is coming off as especially confusing since I came from a Unibill background and was expecting Unity IAP/Unity Purchasing to inherit inventory-handling as something ready-made in the plugin. Using PlayerPrefs or some save file system to accomplish this is no big deal, but I spent way too much time wondering why the following never works, when all I should've done is to save any non-consumable product Ids and check if they exist.

    Code (CSharp):
    1. bool hasPurchasedBefore = product.hasReceipt || string.IsNullOrEmpty(product.receipt) == false || string.IsNullOrEmpty(product.transactionID) == false;
    2. bool canPurchaseMore = (productType == ProductType.Consumable) ? true : (!hasPurchasedBefore);
    Clarification: above code is something I tried, not something I'd recommend; it seems the hasReceipt and receipt fields are entirely unreliable and won't store information in Editor and certainly won't function equally across various platforms.
     
    ap-unity likes this.
  11. ap-unity

    ap-unity

    Unity Technologies

    Joined:
    Aug 3, 2016
    Posts:
    1,519
    @Meatgrind,

    Thank you for the feedback. We are working to improve our documentation and this is something we could definitely make more clear.
     
Thread Status:
Not open for further replies.