Search Unity

Official Unity IAP FAQs

Discussion in 'Unity IAP' started by nicholasr, Feb 25, 2016.

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

    jevin05

    Joined:
    Apr 7, 2013
    Posts:
    5
    Last edited: Jul 22, 2016
    erika_d likes this.
  2. rmassanet

    rmassanet

    Joined:
    Apr 17, 2014
    Posts:
    5
    Hi, I am trying to migrate to Unity IAP and I'm having some trouble with purchases that are left pending (for private server validation).

    My ProcessPurchase method returns PurchaseProcessingResult.Pending, because the validation process takes place later on. I understand from the docs that pending purchases are persisted (not sure where), and on the next purchase or app restart, my ProcessPurchase method should be called again upon them. But I'm not seeing this happen.

    So, my question is: is there any reason why the ProcessPurchase method of my IStoreListener would not be called upon pending purchases? I read in the FAQ a possible reason for iOS devices (a third-party plugin consuming store events), but I'm experiencing the problem in Android too.

    I have updated to 5.3.6p1, encouraged by reading this:

    IAP: Fixed IAP IStoreListener.ProcessPurchase method not being called if Unity IAP was informed of a purchase for a product which was not requested during initialisation.​

    But the problem persists.

    Thanks in advance.
     
  3. rmassanet

    rmassanet

    Joined:
    Apr 17, 2014
    Posts:
    5
    I haven't figured out why the ProcessPurchase method was not being called, but I finally solved it re-importing the Unity In-App Purchasing package.

    I have gone through the changelog of the package and I don't see any fix that affects both iOS and Android, so maybe the fix is a combination of re-importing the package and upgrading to Unity 5.3.6?

    If a suggestion is allowed, I think I would have found the solution much faster if the Unity Editor had given me the advice to re-import the In-App Purchasing package.

    Anyway, I think I read the suggestion of re-importing the package in this forum, so thanks for your help!
     
    erika_d likes this.
  4. erika_d

    erika_d

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

    Just to clarify, is your suggestion that whenever there is a new version of IAP that the Editor gives you a pop up letting you know there's a new version and suggesting the reimport? It seems like a good idea; I will pass the suggestion on to our IAP team!
     
  5. rmassanet

    rmassanet

    Joined:
    Apr 17, 2014
    Posts:
    5
    Yes, @erika_d, I think that would be very helpful.

    Thanks a lot!
     
  6. erika_d

    erika_d

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

    It sounds like this is already on our roadmap! Too soon to have any idea of a release date, but looks like it will be a feature in the future! :)
     
  7. rmassanet

    rmassanet

    Joined:
    Apr 17, 2014
    Posts:
    5
    Great, thanks, @erika_d!

    I do have another question. Now that I am finally on the road again, I have encountered what looks like an incoherence. But I thought I'd ask, because maybe it's expected behaviour.

    This is the scenario, in an iOS (Apple Store) system:
    1. The user purchases an consumable item.
    2. The IStoreListener returns PurchaseProcessingResult.Pending, because validation occurs later on.
    3. For whatever reason, validation cannot be performed at the time, so the transaction is left as pending.
    4. Repeat 1-3 one more time.
    5. Reset the application, so that Unity IAP will try to process the pending purchases.
    The problem is that now, I have two pending purchases, and thus, two calls to ProcessPurchase. Surprisingly, each purchase has an AppReceipt associated, containing two IAPReceipts. So, when I process both purchases, I am actually processing the same item twice.

    Since I don't have a way of querying pending purchases, and I can't modify Apple Store's receipt payload because it is ASN.1 encoded and signed, I can't find a way to reliably process each item only once. Can I expect that Apple Store purchases will always come bundled in one single receipt, so I should process only one pending purchase and discard others?

    I would say an IAP purchase should only have an IAPReceipt associated to it, not an AppReceipt. But I am no Apple Store expert, maybe that is just not possible...

    Could you point me in the right direction to work around this?

    Thanks again!
     
  8. MochiBits

    MochiBits

    Joined:
    Mar 11, 2014
    Posts:
    30
    How does purchase restoration work for Amazon?

    If I understand correctly, the amazon sdk allows for a call to PurchasingService.getPurchaseUpdates(true) to get a list of all purchases.

    Does this get called automatically with Unity IAP on startup? or is there a way to call it so we can implement a Restore Purchases button like iOS?

    Thanks!
     
  9. erika_d

    erika_d

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

    Yes this should get called automatically on startup. Additionally, if you want to add a Restore Purchases button, you should be able to in Editor version 5.4 by using the FetchAdditionalProducts method to trigger the restore check.
     
  10. erika_d

    erika_d

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

    Do the two purchases you're seeing have different transaction IDs or are they the same? https://docs.unity3d.com/ScriptReference/Purchasing.Product-transactionID.html

    If they are different transaction IDs than it sounds like this is expected behavior given that it seems like Apple allows multiple purchases of the same (consumable) product. However if you're seeing the same transaction ID for both purchases, than this may be a bug in our system.

    Also I would not suggest discarding other pending purchases, as it is possible that multiple purchases could be pending. When our system goes through and attempts to fulfill the purchase with your app, as long as the first purchase is marked as complete, it will not interfere with the second one (despite each purchase having the full Apple receipt).
     
  11. MochiBits

    MochiBits

    Joined:
    Mar 11, 2014
    Posts:
    30
    Thanks @erika_d.

    So if I understand correctly, FetchAdditionalProducts will refresh the product dictionary Purchasing.IStoreController.products, and the receipt property in each product will either be null or have a valid receipt if that productId was purchased?
     
  12. erika_d

    erika_d

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

    Yes, you are correct that FetchAdditionalProducts will add any new products not already known by the app to the products list and the receipt property should be either null or have a receipt if the product was purchased.
     
    nicholasr likes this.
  13. yuewahchan

    yuewahchan

    Joined:
    Jul 2, 2012
    Posts:
    309
    Is it possible to return if ConfirmPendingPurchase is success or not ?
     
  14. eab6863

    eab6863

    Joined:
    Feb 12, 2015
    Posts:
    4
    I've just started using the Unity IAP but I can't find where to create products. I'm following the manual to define products but I can't find where in the Analytics Dashboard to define my products.

    Is this a new feature coming to the dashboard? Or am I just missing where to create my products?
     
  15. erika_d

    erika_d

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

    You don't need to define products on the Analytics dashboard, although you will need to define them on your developer consoles (Google, Apple, etc), and then in the app make sure that the id's you gave on the developer consoles match the ids you've defined by following the manual and you should be good to go.

    Note that it can take awhile once products have been created in the consoles before they will be available to your app.
     
    Last edited: Aug 17, 2016
    nicholasr likes this.
  16. erika_d

    erika_d

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

    ConfirmPendingPurchase doesn't have a return value, but purchases that fail to confirm/finish will be automatically retried to finish on app relaunch.
     
    nicholasr likes this.
  17. yuewahchan

    yuewahchan

    Joined:
    Jul 2, 2012
    Posts:
    309
    Instead of retry on app relaunch, is it possible to add feature to retry manually?
     
  18. nicholasr

    nicholasr

    Joined:
    Aug 15, 2015
    Posts:
    183
    @yuewahchan What situation / scenario would be one where retry manually would be desirable? Would you mind provide motivating detail please to help us characterize the need?

    As @erika_d said the retry is automatic on relaunch, currently. When a developer first calls ConfirmPendingPurchase to finish the transaction the transaction ID is recorded locally and the native confirmation / finishing / consuming API is called, for platforms that have one. Currently GooglePlay and Windows Store return a consumption / finishing result code. Amazon, Apple iOS/Mac, Samsung Galaxy Apps, and I believe also Samsung Tizen IAP do not. Assuming the consumption fails, when the user relaunches the application, most platforms will again notify the application of the transactions pending completion. Unity IAP will see the transaction ID in its local database and bypass notifying the application, then automatically call the finishing API again.
     
  19. yuewahchan

    yuewahchan

    Joined:
    Jul 2, 2012
    Posts:
    309
    Our game use server receipt validation. When the server response is failed, it can not validate again immediately.
     
  20. yuewahchan

    yuewahchan

    Joined:
    Jul 2, 2012
    Posts:
    309
    Oh, I found that I can get the product receipt locally to validate again.
     
    erika_d likes this.
  21. pus2meong

    pus2meong

    Joined:
    May 3, 2012
    Posts:
    83
    Hi, I'm using Unity 5.3 and dealing with IAP for the first time.

    In my project, I got subscription purchase.
    Purchasing process was success and the receipt is valid.

    However, when I cancel the subscription, the product receipt does not return null for a product that no longer owned by the player.
    The purchase receipt also saying about valid time on the day it was canceled. So I waited until the expiration time, but the receipt still not returning null.

    How do I check if the player is no longer had subscription in my game if the product receipt still available?


    Sorry for all of grammars error, English is not my native language..
     
  22. erika_d

    erika_d

    Joined:
    Jan 20, 2016
    Posts:
    413
  23. bkachmar

    bkachmar

    Joined:
    Mar 15, 2013
    Posts:
    43
    Hello @nicholasr , @erika_d

    I just updated to stable version of Unity 5.4.0f3 and thought that this would be solved in new build, but I still cannot use FetchAdditionalProducts =(
    It looks like I am having a wrong understanding of what's happening and am doing something wrong.

    Is this the correct order of things?
    - ConfigurationBuilder builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
    - In a loop add first 50 items: builder.AddProduct(currentId, ProductType.NonConsumable);
    - UnityPurchasing.Initialize(this, builder);
    - Wait for OnInitialized(IStoreController controller, IExtensionProvider extensions)
    - Set controller and extensions to class fields
    - Wait two frames (to display my Debug.Logs)
    - HashSet<ProductDefinition> itemsHashSet = new HashSet<ProductDefinition>();
    - In a loop: itemsHashSet.Add(new ProductDefinition(allIds, ProductType.NonConsumable));
    - m_StoreController.FetchAdditionalProducts(itemsHashSet, OnProductsFetched, OnInitializeFailed);

    After I Initialize store with ConfigurationBuilder I can make a purchase:
    Product product = m_StoreController.products.WithID(productId);
    m_StoreController.InitiatePurchase(product);
    And everything works fine, but after I receive OnProductsFetched event when I do the same action I always get an error:

    ArgumentException: The requested value 'ItemUnavailable' was not found.


    at System.Enum.Parse (System.Type enumType, System.String value, Boolean ignoreCase) [0x00000] in <filename unknown>:0

    at System.Enum.Parse (System.Type enumType, System.String value) [0x00000] in <filename unknown>:0

    at UnityEngine.Purchasing.JSONSerializer.DeserializeFailureReason (System.String json) [0x00000] in <filename unknown>:0

    at UnityEngine.Purchasing.AppleStoreImpl.ProcessMessage (System.String subject, System.String payload, System.String receipt, System.String transactionId) [0x00000] in <filename unknown>:0

    at UnityEngine.Purchasing.Extension.UnityUtil.Update () [0x00000] in <filename unknown>:0

    Do you know what I am doing wrong, or are there any examples of FetchAdditionalProducts implementation that doesn't break my store?

    Best,
    Bohdan
     
  24. ap-unity

    ap-unity

    Unity Technologies

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

    I noticed you have a Unity Answers post with a similar issue: Am I correct in assuming this is the same error?
    http://answers.unity3d.com/questions/1234992/fetchadditionalproducts-makes-products-unavailable.html

    I am curious why you are using FetchAdditionalProducts in this case? It looks like you are breaking up your products into groups of 50. Is there are particular reason for this. The UA post mentions you have 1300+ products. Were you experiencing slowdown loading them all?

    As for the errors you're getting, would you be able to post the code that is raising this exception and the full debug log from the application start to when the error happens?
     
  25. manny003

    manny003

    Joined:
    Mar 18, 2014
    Posts:
    70
    Can I get a definitive answer, because I can't find anything, about whether Unity 5.4.1p1 supports IAP for Apple TVOS? My project fails to build and need to know if I'm spinning my wheels trying to fix something that is not supported.

    I recall reading on a Road Map once that is was supposed to be support in version 5.4.x but have heard nothing since. My questions about this to Unity Answer and other forums remains unanswered.

    Thanks,
    Manny
     
  26. webprom

    webprom

    Joined:
    Apr 30, 2016
    Posts:
    12
    Hello.
    I have a problem with fetching metadata.lacalpricetostring from Google play store.
    The problem is that in first time everything work perfectly. But if i change the price in Google dashboard in the app i continue to see old price. Unity 5.4.1f1
    1) Is all metada store locally and fetching only once?
    2) How i can refresh data? I had read about FetchAdditionalProducts, but not understand how i can use it for existing products

    UPDATE:After few hours of waiting, the local price metadata had change buy it self.
    3) What is the waiting time to refresh all data?
     
    Last edited: Sep 21, 2016
  27. ap-unity

    ap-unity

    Unity Technologies

    Joined:
    Aug 3, 2016
    Posts:
    1,519
  28. bkachmar

    bkachmar

    Joined:
    Mar 15, 2013
    Posts:
    43
    Hello,

    First of all thanks for the reply. I didn't get a notification, so that's why I didn't react on time.

    Yes, the issue described in my Unity Answers post is the same and by now I use Unity 5.4.1f1.

    Currently in live version of my application I don't use FetchAdditionalProducts, but the initialization time is usually more than a minute (50-80 seconds). By now the number of items is 1600+ and it's constantly increasing.
    And I want our users to be able to see the price and be able to purchase at least first 50 highlighted products right away.
    It doesn't make sense for them to wait until all 1600+ products will be initialized.

    In my code I have a big list of stings with ids from only NonConsumable products.
    At the beginning I take first 100 and builder.AddProduct(highlightedId, ProductType.NonConsumable);
    Then UnityPurchasing.Initialize(this, builder);
    This operation takes a few seconds and that's totally not a problem.
    At this point I can successfuly call m_StoreController.InitiatePurchase(product);

    After that I repeat the same sequence:
    Untill there are not initialized products in the list
    {
    I wait two frames, create a hash set HashSet<ProductDefinition> itemsHashSet = new HashSet<ProductDefinition>();
    Add next 100 products itemsHashSet.Add(new ProductDefinition(id, ProductType.NonConsumable));
    m_StoreController.FetchAdditionalProducts(itemsHashSet, OnProductsFetched, OnInitializeFailed);
    }

    I always get successful callback after FetchAdditionalProducts, but the purchasing just stops working.
    Product product = m_StoreController.products.WithID(productId);
    if (product != null && product.availableToPurchase)
    {
    Debug.Log(string.Format("Purchasing product asychronously: '{0}'", product.definition.id));
    // ... buy the product. Expect a response either through ProcessPurchase or OnPurchaseFailed asynchronously.
    m_StoreController.InitiatePurchase(product);
    }

    In the trace log I get this:
    purchase({0}): com.tombooks.tomplayipad.17432

    IAPManager:BuyItem(String)
    <DownloadSongInThreeLanguagesCoroutine>c__Iterator2C:MoveNext()
    UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)


    (Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineDebugBindings.gen.cpp Line: 42)

    ArgumentException: The requested value 'ItemUnavailable' was not found.
    at System.Enum.Parse (System.Type enumType, System.String value, Boolean ignoreCase) [0x00000] in <filename unknown>:0
    at UnityEngine.Purchasing.JSONSerializer.DeserializeFailureReason (System.String json) [0x00000] in <filename unknown>:0
    at UnityEngine.Purchasing.NativeJSONStore.OnPurchaseFailed (System.String json) [0x00000] in <filename unknown>:0
    at UnityEngine.Purchasing.AppleStoreImpl.ProcessMessage (System.String subject, System.String payload, System.String receipt, System.String transactionId) [0x00000] in <filename unknown>:0
    at UnityEngine.Purchasing.Extension.UnityUtil.Update () [0x00000] in <filename unknown>:0


    (Filename: currently not available on il2cpp Line: -1)

    Once again, after first initialisation I call FetchAdditionalProducts and untill I get a successful callback purchasing works. But after the callback I send another FetchAdditionalProducts request, and this error happens all the time.

    Best,
    Bohdan
     
    Last edited by a moderator: Sep 28, 2017
  29. bkachmar

    bkachmar

    Joined:
    Mar 15, 2013
    Posts:
    43
    And one more question, @ap-unity ,

    After I initialize my store I walk through my products and check m_StoreController.products.WithID(IdsToCheckReceipt).hasReceipt

    I have some purchases on my account and when I restore purchases I receive a lot of them, but none of my products have receipts.
    Is there a possibility to check if I have already purchased this product, or not?

    Best,
    Bohdan
     
  30. gilberto_lumentech

    gilberto_lumentech

    Joined:
    May 6, 2016
    Posts:
    10
    Guys... I'm having one big issue using the UnityPurchasing.Initialize in Android (only Android)...

    Sometimes (only sometimes...), the UnityPurchasing is Initialized (with success) without internet (in airplane mode)...

    We're using a Sandbox Environment.

    But we can't make any buy, of course, because we are in Airplane Mode...

    Steps:

    1º - Entered the game WITH INTERNET
    2º - Try to buy something
    3º - When we get the "Purchased successfully" from GooglePlay, we close the game (then the Unity don't call the success Purchase, neither fail purchase). The purchase is know pending. The expected behaviour is to call the respective callback when I restart the game.
    4º - Entered the game IN AIRPLANE MODE
    5º - The UnityPurchasing Initialize (why...). It calls the callback too (ProcessPurchase)... We can give the correctly rewards (we made a cache of the packages).

    If we close the game and enter again (still in Airplane Mode), he don't call ProcessPurchase again... He logs a message: "Already recorded transaction".

    If we enter the game with internet, then he log "Already recorded transaction". But after that, he doesn't log anymore the "Already recorded transaction"... Probably made a request of that, corfirming the purchase.

    The weird behaviour is that the UnityPurchasing is Initializing correctly without internet! This doesn't happen all the times. If we restart the game, the correct behaviour is restored (but if we do the above steps a few times, it starts to begin...).

    ------------------

    TL;DR:

    Why UnityPurchasing.Initialize is calling OnInitialized, meaning that it initialized successfully, in airplane mode?
     
  31. ap-unity

    ap-unity

    Unity Technologies

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

    We are looking into any issues with FetchAdditionalProducts. We are also looking to create documentation on how to properly implement that feature. I will post a message here when we have more details.

    Regarding hasReceipt, that is expected behavior for iOS. You would have to parse the Unified receipt Apple has to get owned products. There's a discussion about this in this thread:
    https://forum.unity3d.com/threads/hasreceipt-still-false-on-ios-after-restart.433520/

    Hi @gilberto_lumentech,
    This is expected behavior. Unity IAP is able to be initialized without an internet connection. However, purchases will not go through, as expected. Because the products are defined in code, an internet connection is not required until a purchase needs to be made.
     
  32. bkachmar

    bkachmar

    Joined:
    Mar 15, 2013
    Posts:
    43
    Hi @ap-unity

    Looking forward to hear any news regarding bug fixes in this area.
    This would actually boost my application's store launch time from 80+ seconds to 2 seconds for highlighted scores and to 10 seconds for user cases.

    Best,
    Bohdan
     
  33. PixelEnvision

    PixelEnvision

    Joined:
    Feb 7, 2012
    Posts:
    513
    After receiving a similar error I've ended up in this thread.

    When I set Amazon App Testers Purchase API to respond with INVALID_SKU, Unity IAP (1.8.3) fails with the following error on device logcat.

    Code (CSharp):
    1. ArgumentException: The requested value 'ItemUnavailable' was not found.
    2. at System.Enum.Parse (System.Type enumType, System.String value, Boolean ignoreCase) [0x00000] in <filename unknown>:0
    3. at UnityEngine.Purchasing.JSONSerializer.DeserializeFailureReason (System.String json) [0x00000] in <filename unknown>:0
    4. at UnityEngine.Purchasing.NativeJSONStore.OnPurchaseFailed (System.String json) [0x00000] in <filename unknown>:0
    5. at UnityEngine.Purchasing.AppleStoreImpl.ProcessMessage (System.String subject, System.String payload, System.String receipt, System.String transactionId) [0x00000] in <filename unknown>:0
    6. at UnityEngine.Purchasing.Extension.UnityUtil.Update () [0x00000] in <filename unknown>:0
    7.  
    FAILED & ALREADY_PURCHASED responses seems ok.
     
  34. ap-unity

    ap-unity

    Unity Technologies

    Joined:
    Aug 3, 2016
    Posts:
    1,519
  35. Suguma

    Suguma

    Joined:
    May 29, 2015
    Posts:
    26
    Hello!

    I'd like to ask about testing Unity IAP on Mac. I have an app for iOS and Mac, and the iOS version works just fine. I wanted to test the mac version, but I am unable to run the signed build. I followed the instructions on https://docs.unity3d.com/Manual/UnityIAPiOSMAS.html, but after I enable Mac App Store Validation, I just cannot run the app. If I install the signed pkg, I'm prompted with a "This app is damaged" error.

    Is there a way of testing Unity IAP on Mac?
     
  36. ap-unity

    ap-unity

    Unity Technologies

    Joined:
    Aug 3, 2016
    Posts:
    1,519
  37. ap-unity

    ap-unity

    Unity Technologies

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

    We are looking into that issue with Amazon Testers Purchase API. Thanks for alerting us to it.
     
  38. TimberX

    TimberX

    Joined:
    Jul 20, 2016
    Posts:
    11
    Hi Unity,
    I am using UnityIAP and my editor version is Unity 5.3.6. I have only one non-consumable product for both Android and iOS. On Android things are working well, I use product.hasReceipt to check if a user has purchased the product before. However, on iOS, my app is uploaded to itunesconnect as a beta test, our tester can purchase it under the sandbox environment. When they want to purchase it again it has a prompt that " You have already purchased, do you want to purchase again?". The issue is that product.hasReceipt is false everytime when I restart the app. I wonder does it only happen to the sankbox environment? Will product.hasReceipt work when the app is live? Or can I have another solution for Apple to detect a user purchased the non consumable product before under both sandbox environment and live?
    Thanks.
     
  39. TimberX

    TimberX

    Joined:
    Jul 20, 2016
    Posts:
    11
    I got the solution for above from https://docs.unity3d.com/Manual/UnityIAPValidatingReceipts.html.
    Code (CSharp):
    1. #if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX
    2. var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
    3. // Get a reference to IAppleConfiguration during IAP initialization.
    4. var appleConfig = builder.Configure<IAppleConfiguration>();
    5. var receiptData = System.Convert.FromBase64String(appleConfig.appReceipt);
    6. AppleReceipt receipt = new AppleValidator(AppleTangle.Data()).Validate(receiptData);
    7.  
    8. Debug.Log(receipt.bundleID);
    9. Debug.Log(receipt.receiptCreationDate);
    10. foreach (AppleInAppPurchaseReceipt productReceipt in receipt.inAppPurchaseReceipts) {
    11.     Debug.Log(productReceipt.transactionIdentifier);
    12.     Debug.Log(productReceipt.productIdentifier);
    13. }
    14. #endif
    The local receipts works for restarting the app when I am in the sandbox test environment, but the local receipts data will be deleted when the user reinstall the app. I think the receipt is expected to linked to the apple ID account, not sure will the local receipt validation way or the product.hasReceipt work when the app is on live?
     
  40. ap-unity

    ap-unity

    Unity Technologies

    Joined:
    Aug 3, 2016
    Posts:
    1,519
    TimberX likes this.
  41. 00christian00

    00christian00

    Joined:
    Jul 22, 2012
    Posts:
    1,035
    Took me a while to figure out so maybe will help someone.
    With the 1.9 version you can't remove store files you don't use as it will break the asset.
    For example I wasn't importing Tizen and WinRT as they were useless for me but the project failed to run then.
     
  42. PanicEnsues

    PanicEnsues

    Joined:
    Jul 17, 2014
    Posts:
    187
    On iOS, I would like to restore purchases on startup, but ONLY if the user is already logged into the iTunes Store (so they're not prompted for their username/password).

    Is there a way to detect whether the user is already logged into iTunes?
     
  43. ap-unity

    ap-unity

    Unity Technologies

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

    Based on some searching, it doesn't look like that is possible:
    http://stackoverflow.com/questions/29482457/ios-check-if-an-itunes-account-is-logged-in
    http://stackoverflow.com/questions/29978794/detect-if-user-is-signed-in-in-the-itunes-store

    And because of that, Apple discourages restoring purchases on startup.

    https://developer.apple.com/library...ceptual/StoreKitGuide/Chapters/Restoring.html
     
  44. PanicEnsues

    PanicEnsues

    Joined:
    Jul 17, 2014
    Posts:
    187
    Thanks! I disagree with Apple's approach to this, just because IME 90% of the time the device user is already logged into the App Store when they launch the game; requiring them to manually restore their purchases seems needlessly clunky.

    So I was hoping for a "best of both worlds" solution, but I guess it's not meant to be. :)
     
  45. dede_touchten

    dede_touchten

    Joined:
    Jul 11, 2012
    Posts:
    6
    Hi,

    Is there any other way to detect whether Android subscription is canceled / expired ?
    From what I understand is that I have to listen to ProcessPurchase after the initialization,
    But I don't seem to get the correct behaviour.

    Could you please elaborate how the ProcessPurchase works on detecting subscription cancellation and expiration?
    Or can we get some List of items that is currently subscribed by the users, instead of listening to ProcessPurchase every app start?
     
  46. keomanla

    keomanla

    Joined:
    Jan 30, 2012
    Posts:
    26
    Unity 5.4.3

    I face with the problem on Android: when I purchased a consumable product and do receipt validation on my server side for the first time, it works ok. But from the second time, I won't be able to buy this item again (it's a money package) because it always return the receipt of previous success purchase, and thus my server won't accept it because it has already been used.

    public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgse)

    I won't return PurchaseProcessingResult.Completed immediately, because I need to do receipt validation with my server so it will return PurchaseProcessingResult.Pending;

    Then later when the validation succeed, I will call ConfirmPendingPurchase(e.purchasedProduct);
    This flow work completely ok on iOS but not Android.

    At first I tested the game using test account (google email added to the list of test users) that was allowed to make purchase without charge, later I remove this email from the list, deleted the app and download it from CH play again, but the problem still existed.

    Here is the code I have, Unity guys please have a look, this bug still occur until now, December 9th 2016.

    Code (CSharp):
    1. public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
    2.     {
    3.         Debug.Log ("Purchase OK: " + e.purchasedProduct.definition.id);
    4.         Debug.Log ("Receipt: " + e.purchasedProduct.receipt);
    5.  
    6.         string receipt = e.purchasedProduct.receipt;
    7.         Dictionary<string, object> wrapper = JSONDotNetHelper.DeserializeObject<Dictionary<string, object>>(receipt);
    8.         if (null == wrapper)
    9.         {
    10.             if (cbFail != null)
    11.             {
    12.                 cbFail("Invalid receipts data");          
    13.             }
    14.             return PurchaseProcessingResult.Complete;
    15.         }
    16.  
    17.         Debug.Log ("Step 1");
    18.  
    19.         foreach (KeyValuePair<string, object> item in wrapper) {
    20.             Debug.LogFormat("Key:{0}\t-\tValue:{1}", item.Key, item.Value);
    21.         }
    22.  
    23.         Debug.Log ("Step 2");
    24.  
    25.         //var store = (string)wrapper["Store"];
    26.         var payload = (string)wrapper["Payload"];
    27.  
    28. #if UNITY_ANDROID
    29.         Dictionary<string, object> details = JSONDotNetHelper.DeserializeObject<Dictionary<string, object>>(payload);
    30.  
    31.         foreach (KeyValuePair<string, object> item in details) {
    32.             Debug.LogFormat("Key:{0}\t-\tValue:{1}", item.Key, item.Value);
    33.         }
    34.  
    35.         Debug.Log ("Step 3");
    36.  
    37.         var json = (string)details["json"]; // This is the INAPP_PURCHASE_DATA information
    38.         var sig = (string)details["signature"]; // This is the INAPP_DATA_SIGNATURE information
    39.  
    40.         Debug.LogFormat("CurrencyCode: {0}", e.purchasedProduct.metadata.isoCurrencyCode);
    41.         Debug.LogFormat("PurchasePrice: {0}", Convert.ToUInt32(e.purchasedProduct.metadata.localizedPrice));
    42.         Debug.LogFormat("ReceiptJson: {0}", json);
    43.         Debug.LogFormat("Signature: {0}", sig);
    44.  
    45.         ValidateGooglePlayPurchaseRequest req = new ValidateGooglePlayPurchaseRequest
    46.         {
    47.             CurrencyCode = e.purchasedProduct.metadata.isoCurrencyCode,
    48.             PurchasePrice = Convert.ToUInt32(e.purchasedProduct.metadata.localizedPrice),
    49.             ReceiptJson = json,
    50.             Signature = sig
    51.         };
    52.  
    53.         PlayFabClientAPI.ValidateGooglePlayPurchase(req, result =>
    54.         {
    55.             _storeController.ConfirmPendingPurchase(e.purchasedProduct);
    56.             GrantPurchase(e.purchasedProduct.definition.id);
    57.             Debug.Log("Validate GooglePlay Success: " + result.ToString());
    58.          
    59.             if (cbSuccess != null)
    60.             {
    61.                 cbSuccess(currentItem);
    62.             }
    63.         }, error =>
    64.         {
    65.             _storeController.ConfirmPendingPurchase(e.purchasedProduct);
    66.             Debug.Log("Validate GooglePlay Fail: " + error.ErrorMessage);
    67.             if (cbFail != null)
    68.             {
    69.                 cbFail(error.ErrorMessage);
    70.             }
    71.         });
    72.  
    73.  
    74. #elif UNITY_IOS
    75.         Debug.LogFormat("CurrencyCode: {0}", e.purchasedProduct.metadata.isoCurrencyCode);
    76.         Debug.LogFormat("PurchasePrice: {0}", Convert.ToUInt32(e.purchasedProduct.metadata.localizedPrice));
    77.         Debug.LogFormat("ReceiptData: {0}", payload);
    78.  
    79.         ValidateIOSReceiptRequest req1 = new ValidateIOSReceiptRequest
    80.         {
    81.             CurrencyCode = e.purchasedProduct.metadata.isoCurrencyCode,
    82.             PurchasePrice = Convert.ToInt32(e.purchasedProduct.metadata.localizedPrice),
    83.             ReceiptData = payload
    84.         };
    85.  
    86.         PlayFabClientAPI.ValidateIOSReceipt(req1, result =>
    87.         {
    88.             _storeController.ConfirmPendingPurchase(e.purchasedProduct);
    89.             GrantPurchase(e.purchasedProduct.definition.id);
    90.             Debug.Log("Validate Apple Success: " + result.ToString());
    91.             if (cbSuccess != null)
    92.             {
    93.                 cbSuccess(currentItem);
    94.             }
    95.         }, error =>
    96.         {
    97.             _storeController.ConfirmPendingPurchase(e.purchasedProduct);
    98.             Debug.Log("Validate Apple Fail: " + error.ErrorMessage);
    99.             if (cbFail != null)
    100.             {
    101.                 cbFail(error.ErrorMessage);
    102.             }
    103.         });
    104. #endif
    105.  
    106.         return PurchaseProcessingResult.Pending;
    107. }
    108.  
     
    Last edited: Dec 22, 2016
  47. keomanla

    keomanla

    Joined:
    Jan 30, 2012
    Posts:
    26
    I'm trying to implement a new store - Slide Me and using OpenIAB for Unity to quickly achieve the native side workload without touching it, via this manual https://docs.unity3d.com/Manual/UnityIAPImplementingAStore.html

    But it's seem that the documentation is not enough for me to handle the cases.
    It would be great if unity guys have some tutorial about it,

    For example there are 2 main classes I should create,
    OpenIABStore implement IStore
    OpenIABStoreController
    implement IStoreController

    OpenIABStore is used when I build a ConfigurationBuilder like this:

    Code (CSharp):
    1.         OpenIABStore openIABModule = OpenIABStore.Instance ();
    2.         ConfigurationBuilder builder = ConfigurationBuilder.Instance (openIABModule);
    When should I create OpenIABStoreController, as in the callback of IStoreListener I saw there is a method

    Code (CSharp):
    1. public void OnInitialized (IStoreController controller, IExtensionProvider extensions)
    When should I call this method on the listener and what should I put there the second parameter IExtensionProvider

    Another question is about the method

    Code (CSharp):
    1. public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
    of the IStoreListener class.

    If for some reason the purchase did not complete, the next time opening the app, how can I ask Unity to trigger this method
    on the listener or I have to call it my self.

    So many ambiguous for me implementing a store following Unity format.

    It would be great if Unity can publish the source code so that we know how the custom Store should be implemented properly.

    I'm thinking about just implement it my way and forward all the purchase flow to my class will be less painful.
     
  48. keomanla

    keomanla

    Joined:
    Jan 30, 2012
    Posts:
    26

    No Unity guys would like to have a look at this ???
     
  49. ap-unity

    ap-unity

    Unity Technologies

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

    The Cross Platform Guide has a lot of good information about the IStoreListener and how to use it:
    https://docs.unity3d.com/Manual/UnityIAPInitialization.html

    Once you have created your custom IStore, your IStoreListener implementation shouldn't need to change that much. The only thing would you need to add is an additional module in the configuration builder (in addition to the StandardPurchasing module).

    https://docs.unity3d.com/Manual/UnityIAPModules.html

    Code (CSharp):
    1. ConfigurationBuilder.Instance (MyCustomModule.Instance(), StandardPurchasingModule.Instance ());

    Most people will create their IStoreController implementations as a monobehaviour and then attach it to a gameobject. The OnInitialized method will be called after you have called UnityPurchasing.Initialize as mentioned in this manual page:
    https://docs.unity3d.com/Manual/UnityIAPInitialization.html

    You can learn more about Store exensions here:
    https://docs.unity3d.com/Manual/UnityIAPModuleExtension.html

    You can see some examples of what other extensions are available in other stores here:
    https://docs.unity3d.com/Manual/UnityIAPiOSMAS.html
    https://docs.unity3d.com/Manual/UnityIAPAmazonExtendedFunctionality.html

    I'm not sure if triggering the purchase again is the right behavior. For example, if the purchase was not complete because the user cancelled it, then it would not be a good idea to try to trigger it again.

    These Manual pages have some useful information regarding how to handle purchases.
    https://docs.unity3d.com/Manual/UnityIAPIStoreHandlingPurchases.html
    https://docs.unity3d.com/ScriptRefe...nsion.IStoreCallback.OnPurchaseSucceeded.html

    When you call OnPurchaseSucceeded, if the application has not already processed a purchase with the supplied tranasaction ID, Unity IAP will invoke the application’s ProcessPurchase method. The ProcessPurchase method is where you would handle fulfillment of the purchased item.

    If the purchase did not complete, then you would call the OnPurchaseFailed method in your IStore implementation.

    https://docs.unity3d.com/ScriptReference/Purchasing.Extension.IStoreCallback.OnPurchaseFailed.html
     
  50. keomanla

    keomanla

    Joined:
    Jan 30, 2012
    Posts:
    26
    Thanks for you reply @ap-unity
    How about the bug on Android only:

    when I purchased a consumable product and do receipt validation on my server side for the first time, it works ok. But from the second time, I won't be able to buy this item again (it's a money package) because it always return the receipt of previous success purchase, and thus my server won't accept it because it has already been used.
     
Thread Status:
Not open for further replies.