Search Unity

[Closed] OnPurchaseFailed with PurchaseFailureReason Unknown for all virtual goods

Discussion in 'Unity IAP' started by correptus, May 5, 2017.

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

    correptus

    Joined:
    Apr 14, 2015
    Posts:
    17
    Hi.
    I am in proccess of implementing Unity IAP for google store, all my virtual goods are currency packs (cunsumable item). At stage of testing i checked every product with test purchases on android device and it was ok. Then I started to messing with reciept validation, suddenly one of my products started to throw OnPurchaseFailed with PurchaseFailureReason.Unknown. I thought it was ok, Im gonna fix that later, but then one by one all of the virtual goods started to throw this fail error. I dont know what is the reason of the problem but i suspect that at some points my ProcessPurchase was stoped by some NullRefs (while I tried to parse reciept json) so it didnt return PurchaseProcessingResult.Complete or PurchaseProcessingResult.Pending, maybe it could broke the goods. Unity does not even call ProcessPurchase anymore, fail happens before it.

    Please help.

    Here is my iap manager class.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine;
    3. using System.Collections;
    4. using UnityEngine.Purchasing;
    5. using System.Text.RegularExpressions;
    6. using UnityEngine.Purchasing.Security;
    7.  
    8. public class IAP : IStoreListener {
    9.  
    10.  
    11.     IStoreController controller;
    12.     IExtensionProvider extensions;
    13.  
    14.  
    15.     public IAP () {
    16.         ConfigurationBuilder builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
    17.         builder.AddProduct("gems_100", ProductType.Consumable);
    18.         builder.AddProduct("gems_500", ProductType.Consumable);
    19.         builder.AddProduct("gems_1000", ProductType.Consumable);
    20.         builder.AddProduct("gems_2500", ProductType.Consumable);
    21.         builder.AddProduct("gems_6000", ProductType.Consumable);
    22.  
    23.         UnityPurchasing.Initialize (this, builder);
    24.     }
    25.  
    26.     public void initiate_purchase(string product_id)
    27.     {
    28.         Debug.Log("initiating purchase");
    29.         controller.InitiatePurchase(product_id);
    30.     }
    31.  
    32.     public void OnInitialized(IStoreController _controller, IExtensionProvider _extensions)
    33.     {
    34.         controller = _controller;
    35.         extensions = _extensions;
    36.     }
    37.  
    38.     public void OnInitializeFailed(InitializationFailureReason error)
    39.     {
    40.         Debug.LogError("OnInitializeFailed " + error.ToString());
    41.     }
    42.  
    43.     public void OnPurchaseFailed(Product i, PurchaseFailureReason p)
    44.     {
    45.         Debug.LogError(p.ToString() + " " + i.definition.id);
    46.     }
    47.  
    48.     public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e)
    49.     {
    50.         bool valid = true;
    51. #if (UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX) && !UNITY_EDITOR
    52.         var validator = new CrossPlatformValidator(GooglePlayTangle.Data(), AppleTangle.Data(), Application.bundleIdentifier);
    53.         try
    54.         {
    55.             IPurchaseReceipt[] validation_result = validator.Validate(e.purchasedProduct.receipt);
    56.         }
    57.         catch (IAPSecurityException)
    58.         {
    59.             Debug.LogError("Invalid receipt, not unlocking content");
    60.             valid = false;
    61.         }
    62. #endif
    63.  
    64.         int gems_count = get_gem_count(e.purchasedProduct.definition.id);
    65.         if (gems_count > 0 && valid)
    66.         {
    67.             Game.data.add_gems(gems_count, (success) =>
    68.             {
    69.                 if (success)
    70.                     controller.ConfirmPendingPurchase(e.purchasedProduct);
    71.             });
    72.             return PurchaseProcessingResult.Pending;
    73.         }
    74.         else
    75.         {
    76.             Debug.Log("invalid purchase");
    77.             return PurchaseProcessingResult.Complete;
    78.         }
    79.     }
    80.  
    81.     int get_gem_count(string product_id)
    82.     {
    83.         Match number = Regex.Match(product_id, @"\d+");
    84.         if (!string.IsNullOrEmpty(number.Value))
    85.         {
    86.             Debug.Log(number.Value);
    87.             return System.Int32.Parse(number.Value);
    88.         }
    89.         else
    90.         {
    91.             Debug.LogError("no number found in product id " + product_id);
    92.             return 0;
    93.         }
    94.     }
    95.  
    96. }
    97.  
    98.  
     
  2. ap-unity

    ap-unity

    Unity Technologies

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

    Looking at your IAP manager, it looks like you are calling ConfirmPendingPurchases from within ProcessPurchase. That is not the intended use of that function and it will result in unexpected behavior (purchase failures and NREs are possible).

    The process is explained in this manual page:
    https://docs.unity3d.com/Manual/UnityIAPProcessingPurchases.html

    If you are saving a purchase to a server, then you may want to return Pending until you are sure that the purchase has been saved. In that case, you would return PurchaseProcessingResult.Pending in your ProcessPurcahse method. And once the purchase has been saved to your server, you would then call (outside of your ProcessPurchase method) ConfirmPendingPurchase.

    If you are not saving your purchases to a server, then you should simply return PurchaseProcessingResult.Complete to let the Purchasing system know that you have completed the transaction.
     
  3. correptus

    correptus

    Joined:
    Apr 14, 2015
    Posts:
    17
    I am calling server to add gems (without server reciept validation atm), then if i got positive responce from a server i am calling ConfirmPendingPurchases (inside callback function).
    My problem is i cant start a single purchase now. Error occurs before ProcessPurchase. So at the moment changing ProcessPurchase affects nothing, and i have zero idea hot to test anything.
     
  4. ap-unity

    ap-unity

    Unity Technologies

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

    How are your products set up in the store? One cause of Unknown purchase failures is trying to repurchase a non-consumable. Are your products defined as a Non-consumable in either the Google Play store.

    Would you be able to provide a device log from when this issue occurs?
     
Thread Status:
Not open for further replies.