Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

IAP return PurchaseFailureReason Unknown. Android (Google Play)

Discussion in 'Unity IAP' started by MaxAskeza, Jan 8, 2021.

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

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Sorry what do you mean on the device side? IAP only works on mobile devices, not in the Editor. And you've published to a test track then downloaded your app from Google Play to test, correct?
     
  2. ABerlemont

    ABerlemont

    Joined:
    Sep 27, 2012
    Posts:
    67
    I meant that I think the issue is linked to the device I'm using and that the build could be fine on some other devices.

    We actually managed to have another outcome on 1 out of 4 devices where the price was showing (instead of the usual "the item you requested is not available for purchase").

    But we are not sure why yet.

    And yes : we publish the build on play console in the internal testing flow and download the app through the store.
     
    Last edited: May 11, 2021
  3. ABerlemont

    ABerlemont

    Joined:
    Sep 27, 2012
    Posts:
    67
  4. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
  5. kevinsquid

    kevinsquid

    Joined:
    Jul 4, 2018
    Posts:
    1
    I am able to reproduce this same issue on 2019.4 by cancelling the Purchase request.

    If I start the purchase then accept, the purchase goes through fine, its only when cancelled that I encounter

    07-26 12:52:45.733: W/BillingHelper(10260): Couldn't find purchase lists, trying to find single data.
    07-26 12:52:45.738: W/BillingHelper(10260): Received a bad purchase data.
    07-26 12:52:45.739: W/BillingHelper(10260): Couldn't find single purchase data as well.
    07-26 12:52:47.561: W/Unity(10260): onPurchaseFailedEvent(productId:XXXXX_OUR_IAP_CODE message:)
    07-26 12:52:47.561: W/Unity(10260): UnityEngine.Purchasing.PurchasingManager:OnPurchaseFailed(PurchaseFailureDescription)
     
  6. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    The error should be UserCancelled in this case. Also, ensure that you are using a tester account and have opted into testing by browsing to the opt-in URL on the device first, then downloading from Closed testing on Google Play
     
  7. Funtyx

    Funtyx

    Joined:
    May 3, 2017
    Posts:
    29
    I'm using IAP Button, when testing, if I buy the product everything works fine, but if I cancel, I get an error and I can't reset the game to its original state before the purchase. As far as I understand, when canceling a purchase, On Purchase Failed should be called, but this does not work and causes an error.

    upload_2022-3-27_19-37-58.png

    upload_2022-3-27_19-38-21.png
     
  8. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    You can only make an actual purchase on a device, not through the fake store in the Editor. On a device, OnPurchaseFailed is indeed called. Also, you'll want to avoid Codeless IAP, it has not been updated in some time and is missing features. You might want to start with the Sample IAP Project here: https://forum.unity.com/threads/sample-iap-project.529555/#post-7922275
     
  9. Funtyx

    Funtyx

    Joined:
    May 3, 2017
    Posts:
    29
    I created a script based on your examples, purchase and restore. The problem did not disappear, in the Unity editor in the Fake window, when I click cancel, a warning appears referring in PurcasingManager.cs to the following code:

    public void OnPurchaseFailed(PurchaseFailureDescription description)
    {
    if (description != null)
    {
    var product = products.WithStoreSpecificID(description.productId);
    if (null == product)
    {
    m_Logger.LogFormat(LogType.Error, "Failed to purchase unknown product {0}", "productId:" + description.productId + " reason:" + description.reason + " message:" + description.message);
    return;
    }

    m_Logger.LogFormat(LogType.Warning, "onPurchaseFailedEvent({0})", "productId:" + product.definition.id + " message:" + description.message);
    m_Listener.OnPurchaseFailed(product, description.reason);
    }
    }

    At the same time, in my code it does not always work:
    public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
    {
    onPurchaseFailed.Invoke(product, failureReason);
    Debug.Log($"Purchase failed - Product: '{product.definition.id}', PurchaseFailureReason: {failureReason}");
    }
    The Debug.Log appears but onPurchaseFailed.Invoke(product, failureReason); does not work

    Below are screenshots of warnings in Unity and in Xcode, as well as the generated code. Please help me figure it out!

    Unity:
    upload_2022-3-28_19-54-1.png

    upload_2022-3-28_19-57-42.png

    Xcode:
    upload_2022-3-28_19-55-54.png

    Code (CSharp):
    1. using UnityEngine.Events;
    2. using System;
    3.  
    4. namespace UnityEngine.Purchasing
    5. {
    6.     public class PurchaseManager : MonoBehaviour, IStoreListener
    7.     {
    8.         [System.Serializable]
    9.         public class OnPurchaseCompletedEvent : UnityEvent<Product>
    10.         {
    11.         };
    12.  
    13.         [System.Serializable]
    14.         public class OnPurchaseFailedEvent : UnityEvent<Product, PurchaseFailureReason>
    15.         {
    16.         };
    17.  
    18.         private static IStoreController _mStoreController;
    19.         private static IExtensionProvider _mStoreExtensionProvider;
    20.  
    21.         public string productId;
    22.  
    23.         [Header("Purchase Events")]
    24.         public OnPurchaseCompletedEvent onPurchaseComplete;
    25.         public OnPurchaseFailedEvent onPurchaseFailed;
    26.  
    27.         [Header("Restore Events")]
    28.         public UnityEvent restoreSuccess;
    29.         public UnityEvent restoreNoReciept;
    30.         public UnityEvent restoreFail;
    31.  
    32.         private void Start()
    33.         {
    34.             if (_mStoreController == null)
    35.             {
    36.                 InitializePurchasing();
    37.             }
    38.         }
    39.  
    40.         public void InitializePurchasing()
    41.         {
    42.             if (IsInitialized())
    43.             {
    44.                 return;
    45.             }
    46.  
    47.             var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
    48.  
    49.             builder.AddProduct(productId, ProductType.NonConsumable);
    50.  
    51.             UnityPurchasing.Initialize(this, builder);
    52.         }
    53.  
    54.         private bool IsInitialized()
    55.         {
    56.             return _mStoreController != null && _mStoreExtensionProvider != null;
    57.         }
    58.  
    59.         public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    60.         {
    61.             Debug.Log("In-App Purchasing successfully initialized");
    62.  
    63.             _mStoreController = controller;
    64.             _mStoreExtensionProvider = extensions;
    65.         }
    66.  
    67.         public void BuyFullVersion()
    68.         {
    69.             _mStoreController.InitiatePurchase(productId);
    70.         }
    71.  
    72.         public void Restore()
    73.         {
    74.             if (!IsInitialized())
    75.             {
    76.                 return;
    77.             }
    78.  
    79.             if (Application.platform == RuntimePlatform.IPhonePlayer ||
    80.                 Application.platform == RuntimePlatform.OSXPlayer ||
    81.                 Application.platform == RuntimePlatform.tvOS)
    82.             {
    83.                 var apple = _mStoreExtensionProvider.GetExtension<IAppleExtensions>();
    84.  
    85.                 apple.RestoreTransactions(OnRestore);
    86.             }
    87.  
    88.             else if (Application.platform == RuntimePlatform.Android &&
    89.                             StandardPurchasingModule.Instance().appStore == AppStore.GooglePlay)
    90.             {
    91.                 var google = _mStoreExtensionProvider.GetExtension<IGooglePlayStoreExtensions>();
    92.  
    93.                 google.RestoreTransactions(OnRestore);
    94.             }
    95.  
    96.             else
    97.             {
    98.                 Debug.LogWarning(Application.platform.ToString() + " is not a supported platform for the Codeless IAP restore button");
    99.                 OnRestore(false);
    100.             }
    101.         }
    102.  
    103.         //
    104.         // --- Restore Purchase
    105.         //
    106.         private void OnRestore(bool success)
    107.         {
    108.             if (success)
    109.             {
    110.                 Product product = _mStoreController.products.WithID(productId);
    111.  
    112.                 if (product != null && product.hasReceipt)
    113.                 {
    114.                     restoreSuccess.Invoke();
    115.                 }
    116.                 else
    117.                 {
    118.                     restoreNoReciept.Invoke();
    119.                 }
    120.             }
    121.             else
    122.             {
    123.                 restoreFail.Invoke();
    124.             }
    125.         }
    126.  
    127.         // --- PurchaseProcessingResult
    128.         public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
    129.         {
    130.             if (String.Equals(args.purchasedProduct.definition.id, productId, StringComparison.Ordinal))
    131.             {
    132.                 onPurchaseComplete.Invoke(args.purchasedProduct);
    133.                 Debug.Log(string.Format("ProcessPurchase: PASS. Product: '{0}'", args.purchasedProduct.definition.id));
    134.             }
    135.  
    136.             else
    137.             {
    138.                 Debug.Log(string.Format("ProcessPurchase: FAIL. Unrecognized product: '{0}'", args.purchasedProduct.definition.id));
    139.             }
    140.  
    141.             return PurchaseProcessingResult.Complete;
    142.         }
    143.  
    144.         // --- OnInitializeFailed - Error
    145.         public void OnInitializeFailed(InitializationFailureReason error)
    146.         {
    147.             Debug.Log("OnInitializeFailed InitializationFailureReason:" + error);
    148.         }
    149.  
    150.         // --- OnInitializeFailed - Purchase failed
    151.         public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
    152.         {
    153.             onPurchaseFailed.Invoke(product, failureReason);
    154.             Debug.Log($"Purchase failed - Product: '{product.definition.id}', PurchaseFailureReason: {failureReason}");
    155.         }
    156.     }
    157. }
    158.  
     

    Attached Files:

  10. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    @Funtyx You can see in the logs that OnPurchaseFailed is called with reason UserCancelled as expected. Since you are using Scripted IAP, you would not want to use an IAP Button or the IAP Catalog. What iOS device are you testing on? Are you testing via TestFlight? This is required to see the actual response, you can't fully test IAP in the Editor, as mentioned. Also, this thread is regarding Google Play, not Apple. Please get the Sample IAP Project working, with no changes. Then add your customizations. Get the basics working first, and build on success instead of chasing bugs. I will go ahead and close this thread. If you continue to have issues with IAP on your iOS device, please open a new thread.
     
Thread Status:
Not open for further replies.