Search Unity

[Solved] Purchasing a Non-Consumable product, rebooting triggers OnPurchaseFailed

Discussion in 'Unity IAP' started by CrystalMD, May 4, 2017.

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

    CrystalMD

    Joined:
    Apr 24, 2016
    Posts:
    4
    DETAILS
    • Unity 5.6.0f3
    • Unity IAP version 1.10.1
    • Android version 5
    I DID
    • Published app in alpha testing
    • Confirmed alpha tester
    • Set up product in store
    • Also tried more 2 different scripts/plugins(from assetstore) and none of them worked
    • I saw the other topic about this issue, but moderators said that it will be fixed in next version, but it seems to persist
    DESCRIPTION
    • Ok, when someone is trying to buy a NON-Consumable product, it's working fine till next restart of app;
    • On second start, game triggers OnPurchaseFailed with error "Dublicate Transaction", not showing what i want(a message for success loading)
    • I'm just trying to find if the following product is purchased.
    USER EXPERIENCE

    IAPManager
    , connector with purchasing system
    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Purchasing;
    5.  
    6. // Deriving the Purchaser class from IStoreListener enables it to receive messages from Unity Purchasing.
    7. public class IAPManager : MonoBehaviour, IStoreListener
    8. {
    9.     public static IAPManager Instance { set; get; }
    10.     private static IStoreController m_StoreController;          // The Unity Purchasing system.
    11.     private static IExtensionProvider m_StoreExtensionProvider; // The store-specific Purchasing subsystems.
    12.  
    13.     public static string EXTRA_FEATURES = "features_1";
    14.  
    15.     private void Awake()
    16.     {
    17.         Instance = this;
    18.     }
    19.  
    20.     private void Start()
    21.     {
    22.         SetReference ();
    23.     }
    24.  
    25.     public bool CheckBuyState(string id)
    26.     {
    27.         SetReference ();
    28.         Product product = m_StoreController.products.WithID(id);
    29.         if (product != null && product.hasReceipt) { return true; }
    30.         else { return false; }
    31.     }
    32.  
    33.     private void SetReference()
    34.     {
    35.         // If we haven't set up the Unity Purchasing reference
    36.         if (m_StoreController == null)
    37.         {
    38.             // Begin to configure our connection to Purchasing
    39.             InitializePurchasing();
    40.         }
    41.     }
    42.  
    43.     public void InitializePurchasing()
    44.     {
    45.         // If we have already connected to Purchasing ...
    46.         if (IsInitialized())
    47.         {
    48.             // ... we are done here.
    49.             return;
    50.         }
    51.  
    52.         // Create a builder, first passing in a suite of Unity provided stores.
    53.         var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
    54.  
    55.         builder.AddProduct(EXTRA_FEATURES, ProductType.NonConsumable);
    56.  
    57.         // Kick off the remainder of the set-up with an asynchrounous call, passing the configuration
    58.         // and this class' instance. Expect a response either in OnInitialized or OnInitializeFailed.
    59.         UnityPurchasing.Initialize(this, builder);
    60.     }
    61.  
    62.  
    63.     private bool IsInitialized()
    64.     {
    65.         // Only say we are initialized if both the Purchasing references are set.
    66.         return m_StoreController != null && m_StoreExtensionProvider != null;
    67.     }
    68.  
    69.  
    70.     public void BuyExtraFeatures()
    71.     {
    72.         BuyProductID(EXTRA_FEATURES);
    73.     }
    74.  
    75.  
    76.     private void BuyProductID(string productId)
    77.     {
    78.         // If Purchasing has been initialized ...
    79.         if (IsInitialized())
    80.         {
    81.             // ... look up the Product reference with the general product identifier and the Purchasing
    82.             // system's products collection.
    83.             Product product = m_StoreController.products.WithID(productId);
    84.  
    85.             // If the look up found a product for this device's store and that product is ready to be sold ...
    86.             if (product != null && product.availableToPurchase)
    87.             {
    88.                 GM.logText.text += string.Format ("Purchasing product asychronously: '{0}'\n", product.definition.id);
    89.                 Debug.Log(string.Format("Purchasing product asychronously: '{0}'", product.definition.id));
    90.                 // ... buy the product. Expect a response either through ProcessPurchase or OnPurchaseFailed
    91.                 // asynchronously.
    92.                 m_StoreController.InitiatePurchase(product);
    93.             }
    94.             // Otherwise ...
    95.             else
    96.             {
    97.                 GM.logText.text += "BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase\n";
    98.                 // ... report the product look-up failure situation
    99.                 Debug.Log("BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase");
    100.             }
    101.         }
    102.         // Otherwise ...
    103.         else
    104.         {
    105.             GM.logText.text += "BuyProductID FAIL. Not initialized.\n";
    106.             // ... report the fact Purchasing has not succeeded initializing yet. Consider waiting longer or
    107.             // retrying initiailization.
    108.             Debug.Log("BuyProductID FAIL. Not initialized.");
    109.         }
    110.     }
    111.  
    112.     public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    113.     {
    114.         GM.logText.text += "OnInitialized: PASS\n";
    115.         // Purchasing has succeeded initializing. Collect our Purchasing references.
    116.         Debug.Log("OnInitialized: PASS");
    117.  
    118.         // Overall Purchasing system, configured with products for this application.
    119.         m_StoreController = controller;
    120.         // Store specific subsystem, for accessing device-specific store features.
    121.         m_StoreExtensionProvider = extensions;
    122.     }
    123.     public void OnInitializeFailed(InitializationFailureReason error)
    124.     {
    125.         GM.logText.text += "OnInitializeFailed InitializationFailureReason:" + error + "\n";
    126.         // Purchasing set-up has not succeeded. Check error for reason. Consider sharing this reason with the user.
    127.         Debug.Log("OnInitializeFailed InitializationFailureReason:" + error);
    128.     }
    129.        
    130.     public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
    131.     {
    132.         if (String.Equals(args.purchasedProduct.definition.id, EXTRA_FEATURES, StringComparison.Ordinal))
    133.         {
    134.             gameObject.GetComponent<GM> ().premiumIcon.SetActive (true);
    135.             GM.logText.text += string.Format("ProcessPurchase: PASS. Product: '{0}'\n", args.purchasedProduct.definition.id);
    136.             Debug.Log(string.Format("ProcessPurchase: PASS. Product: '{0}'", args.purchasedProduct.definition.id));
    137.  
    138.             PlayerPrefs.SetInt ("premium", 1);
    139.             AndroidNativeFunctions.ShowToast ("Purchase confirmed, reload apk", false);
    140.         }
    141.         else
    142.         {
    143.             GM.logText.text += string.Format("ProcessPurchase: FAIL. Unrecognized product: '{0}'\n", args.purchasedProduct.definition.id);
    144.             Debug.Log(string.Format("ProcessPurchase: FAIL. Unrecognized product: '{0}'", args.purchasedProduct.definition.id));
    145.         }
    146.  
    147.         // Return a flag indicating whether this product has completely been received, or if the application needs
    148.         // to be reminded of this purchase at next app launch. Use PurchaseProcessingResult.Pending when still
    149.         // saving purchased products to the cloud, and when that save is delayed.
    150.         return PurchaseProcessingResult.Complete;
    151.     }
    152.  
    153.     public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
    154.     {
    155.         GM.logText.text += string.Format("OnPurchaseFailed: FAIL. Product: '{0}', PurchaseFailureReason: {1}\n", product.definition.storeSpecificId, failureReason);
    156.         // A product purchase attempt did not succeed. Check failureReason for more detail. Consider sharing
    157.         // this reason with the user to guide their troubleshooting actions.
    158.         Debug.Log(string.Format("OnPurchaseFailed: FAIL. Product: '{0}', PurchaseFailureReason: {1}", product.definition.storeSpecificId, failureReason));
    159.     }
    160. }
    161.  
    GameManager, script of the game
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3.  
    4. public class GM : MonoBehaviour {
    5.  
    6.     public GameObject premiumIcon;
    7.     public static Text logText;
    8.  
    9.     void Awake()
    10.     {
    11.         logText = GameObject.Find ("Log").GetComponent<Text> ();
    12.     }
    13.  
    14.     void Start()
    15.     {
    16.         if (IAPManager.Instance.CheckBuyState (IAPManager.EXTRA_FEATURES)) {
    17.             EnablePremium (0);
    18.             return;
    19.         }
    20.         if (PlayerPrefs.GetInt("premium") == 1)
    21.         {
    22.             EnablePremium (1);
    23.         }
    24.     }
    25.  
    26.     void EnablePremium(int i)
    27.     {
    28.         premiumIcon.SetActive (true);  
    29.         if (i == 0) {
    30.             logText.text += "Loaded from IAPManager\n";
    31.             Debug.Log ("Loaded from IAPManager");
    32.             AndroidNativeFunctions.ShowToast ("Loaded from IAPManager", false);
    33.         } else if (i == 1) {
    34.             logText.text += "Loaded from PlayerPrefs\n";
    35.             Debug.Log ("Loaded from PlayerPrefs");
    36.             AndroidNativeFunctions.ShowToast ("Loaded from PlayerPrefs", false);
    37.         }
    38.     }
    39.  
    40.     public void BuyExtra()
    41.     {
    42.         IAPManager.Instance.BuyExtraFeatures ();
    43.     }
    44.  
    45.     public void ClearPrefs()
    46.     {
    47.         if (PlayerPrefs.HasKey ("premium")) {
    48.             PlayerPrefs.DeleteKey ("premium");
    49.             logText.text += "Premium key record was successfuly deleted\n";
    50.             premiumIcon.SetActive (false);
    51.         } else {
    52.             logText.text += "Key not found, maybe already deleted\n";
    53.         }
    54.     }
    55.  
    56. }
    57.  
    Please help me, i really need to solve this problem, i had to update my app on store in nearly future.
     
  2. ap-unity

    ap-unity

    Unity Technologies

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

    This issue should be resolved as of the first patch of 5.6
    https://unity3d.com/unity/qa/patch-releases?version=5.6

    The fix is also available in the following versions:
    2017.1a5
    5.5.3p1
    5.4.5p2
     
  3. CrystalMD

    CrystalMD

    Joined:
    Apr 24, 2016
    Posts:
    4
    @ap-unity

    Ok, but i already have version 5.6.0f3.
    Anyway i manage it somehow to work, all i have done is that i put the purchasing script in previous scene in a non-destroyable object, and when the main scene loaded i put the if statement, and it seems to work, thanks anyway ;)
     
  4. ap-unity

    ap-unity

    Unity Technologies

    Joined:
    Aug 3, 2016
    Posts:
    1,519
    @CrystalMD
    Sorry, I wasn't clear. The fix was in 5.6.0p1. This is the first patch after 5.6.0f3.

    Yes, we are working on some best practice guides, but you want to enable Purchasing as soon as you can in your app and have it available (such as a non-destroyable object) at all times.
     
  5. CrystalMD

    CrystalMD

    Joined:
    Apr 24, 2016
    Posts:
    4
    Thanks a lot @ap-unity for your attention and advice, you can lock this topic :)
    But one last thing, everytime when the script is initializing, one message with DuplicateProduct is showing (in console), but i'm doing nothing in Purchasing script.
     
  6. ap-unity

    ap-unity

    Unity Technologies

    Joined:
    Aug 3, 2016
    Posts:
    1,519
    That should be resolved if you upgrade to 5.6.0p1
    https://unity3d.com/unity/qa/patch-releases?version=5.6
     
Thread Status:
Not open for further replies.