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

Problem with iOS Unity IAP, OnInitializeFailed : No Products Available

Discussion in 'Unity IAP' started by dcavadia, Jun 3, 2021.

  1. dcavadia

    dcavadia

    Joined:
    Aug 27, 2020
    Posts:
    15
    Hello, the current build works well for Android but in iOS it keeps failing at Initializing, returning as a reason: OnInitializeFailed : No Products Available along with Unavailable product nuggets500-nugget500 for each item

    I have an iPhone to test with TestFligh builds generated from the Unity Cloud... I made a build with a console in it to see the errors (since I don't have a mac and Xcode)

    I upload_2021-6-3_16-10-19.png

    After opening the store and triggering the Start in my UnityIAPManager.cs it starts adding the products and initializing the IAP(it stays there for like 1 sec and then fails)
    upload_2021-6-3_16-11-15.png

    upload_2021-6-3_16-12-48.png

    I guess in this case the format in product error is: Unavailable product: ProductID-AppleID

    which is correct
    upload_2021-6-3_16-14-18.png

    All the products are Ready to Submit.

    I also checked the tax form, bank information, and such. I don't know what else to do.. I even deleted all the code implemented and tried with the codeless IAP and still never appears the buy pop-up windows in iOS.

    I used this tutorial https://learn.unity.com/tutorial/unity-iap, so my code is pretty similar.
    My UnityIAPManager.cs, which is attached to the Store Game Object so it triggers when it becomes active in the scene:

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using System.Linq;
    3. using System.Reflection;
    4. using UnityEngine;
    5. using UnityEngine.Purchasing;
    6. using UnityEngine.Purchasing.Security;
    7. // Dragon Garden
    8.  
    9. namespace CoddlePets.DragonGarden
    10. {
    11.     public class UnityIAPProduct
    12.     {
    13.         public string productID;
    14.         public ProductType productType = ProductType.Consumable;
    15.         public IDs storeProductIDs;
    16.     }
    17.     // Deriving the Purchaser class from IStoreListener enables it to receive messages from Unity Purchasing.
    18.     public class UnityIAPManager : SingletonComponent<UnityIAPManager>, IStoreListener
    19.     {
    20.         private static IStoreController m_StoreController;          // The Unity Purchasing system.
    21.         private static IExtensionProvider m_StoreExtensionProvider; // The store-specific Purchasing subsystems.
    22.  
    23.         List<UnityIAPProduct> Products = new List<UnityIAPProduct>();
    24.  
    25.         void Start()
    26.         {
    27.  
    28.             var types = Assembly.GetExecutingAssembly().GetTypes()
    29.                 .Where(t => t.IsSubclassOf(typeof(StoreItemUnityIAP)) && t.FullName != "CoddlePets.DragonGarden.StoreItem")
    30.  
    31.  
    32.                 .ToList();
    33.  
    34.             foreach (var type in types)
    35.             {
    36.                 var product = (StoreItemUnityIAP)Assembly.GetExecutingAssembly().CreateInstance(type.FullName);
    37.  
    38.                 var ids = new IDs { };
    39.                 if (!string.IsNullOrEmpty(product.GoogleProductID))
    40.                 {
    41.                     ids.Add(product.GoogleProductID, new string[] { GooglePlay.Name });
    42.                     Debug.Log("Android: " + product.GoogleProductID);
    43.  
    44.                 }
    45.                 if (!string.IsNullOrEmpty(product.AppleProductID))
    46.                 {
    47.                     ids.Add(product.AppleProductID, new string[] { AppleAppStore.Name });
    48.                     Debug.Log("iOS: " + product.AppleProductID);
    49.  
    50.                 }
    51.  
    52.                 AddProduct(product.ProductID, storeProductIDs: ids);
    53.                 StoreManager.Instance.StoreItems.Add(product);
    54.  
    55.                 Debug.Log("Added: " + product.ProductID);
    56.             }
    57.  
    58.             InitializePurchasing();
    59.  
    60.         }
    61.  
    62.         public void AddProduct(string productID, ProductType productType = ProductType.Consumable, IDs storeProductIDs = null)
    63.         {
    64.             if (!Products.Any(p => p.productID == productID))
    65.             {
    66.                 Products.Add(new UnityIAPProduct { productID = productID, productType = productType, storeProductIDs = storeProductIDs });
    67.             }
    68.         }
    69.  
    70.         public void InitializePurchasing()
    71.         {
    72.             // If we have already connected to Purchasing ...
    73.             if (IsInitialized())
    74.             {
    75.                 // ... we are done here.
    76.                 Debug.Log("Already INIT");
    77.                 return;
    78.             }
    79.  
    80.             // Create a builder, first passing in a suite of Unity provided stores.
    81.             var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
    82.  
    83.             // Add a product to sell / restore by way of its identifier, associating the general identifier
    84.             // with its store-specific identifiers.
    85.  
    86.             foreach (var item in Products)
    87.             {
    88.  
    89.                 if (item.storeProductIDs != null)
    90.                 {
    91.                     builder.AddProduct(item.productID, item.productType, item.storeProductIDs);
    92.                 }
    93.                 else
    94.                 {
    95.                     builder.AddProduct(item.productID, item.productType);
    96.                 }
    97.             }
    98.  
    99.  
    100.             // Kick off the remainder of the set-up with an asynchrounous call, passing the configuration
    101.             // and this class' instance. Expect a response either in OnInitialized or OnInitializeFailed.
    102.             Debug.Log("Call init");
    103.             UnityPurchasing.Initialize(this, builder);
    104.         }
    105.  
    106.  
    107.         private bool IsInitialized()
    108.         {
    109.             // Only say we are initialized if both the Purchasing references are set.
    110.             return m_StoreController != null && m_StoreExtensionProvider != null;
    111.         }
    112.  
    113.  
    114.         public void BuyConsumable(string productId)
    115.         {
    116.             BuyProductID(productId);
    117.         }
    118.  
    119.  
    120.         private void BuyProductID(string productId)
    121.         {
    122.             if (IsInitialized())
    123.             {
    124.                 Product product = m_StoreController.products.WithID(productId);
    125.  
    126.                 if (product != null && product.availableToPurchase)
    127.                 {
    128.                     Debug.Log(string.Format("Purchasing product asychronously: '{0}'", product.definition.id));
    129.                     m_StoreController.InitiatePurchase(product);
    130.                 }
    131.                 // Otherwise ...
    132.                 else
    133.                 {
    134.                     // ... report the product look-up failure situation
    135.                     Debug.Log("Unity IAP Manager BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase");
    136.                 }
    137.             }
    138.             // Otherwise ...
    139.             else
    140.             {
    141.                 // ... report the fact Purchasing has not succeeded initializing yet. Consider waiting longer or
    142.                 // retrying initiailization.
    143.                 Debug.Log("Unity IAP Manager BuyProductID FAIL. Not initialized.");
    144.             }
    145.         }
    146.  
    147.  
    148.         // Restore purchases previously made by this customer. Some platforms automatically restore purchases, like Google.
    149.         // Apple currently requires explicit purchase restoration for IAP, conditionally displaying a password prompt.
    150.         public void RestorePurchases()
    151.         {
    152.             // If Purchasing has not yet been set up ...
    153.             if (!IsInitialized())
    154.             {
    155.                 // ... report the situation and stop restoring. Consider either waiting longer, or retrying initialization.
    156.                 Debug.Log("Unity IAP Manager RestorePurchases FAIL. Not initialized.");
    157.                 return;
    158.             }
    159.  
    160.             // If we are running on an Apple device ...
    161.             if (Application.platform == RuntimePlatform.IPhonePlayer ||
    162.                 Application.platform == RuntimePlatform.OSXPlayer)
    163.             {
    164.                 // ... begin restoring purchases
    165.                 Debug.Log("Unity IAP Manager RestorePurchases started ...");
    166.  
    167.                 // Fetch the Apple store-specific subsystem.
    168.                 var apple = m_StoreExtensionProvider.GetExtension<IAppleExtensions>();
    169.  
    170.                 // Begin the asynchronous process of restoring purchases. Expect a confirmation response in
    171.                 // the Action<bool> below, and ProcessPurchase if there are previously purchased products to restore.
    172.                 apple.RestoreTransactions((result) =>
    173.                 {
    174.                     // The first phase of restoration. If no more responses are received on ProcessPurchase then
    175.                     // no purchases are available to be restored.
    176.                     Debug.Log("Unity IAP Manager RestorePurchases continuing: " + result + ". If no further messages, no purchases available to restore.");
    177.                 });
    178.             }
    179.             // Otherwise ...
    180.             else
    181.             {
    182.                 // We are not running on an Apple device. No work is necessary to restore purchases.
    183.                 Debug.Log("Unity IAP Manager RestorePurchases FAIL. Not supported on this platform. Current = " + Application.platform);
    184.             }
    185.         }
    186.  
    187.  
    188.         //
    189.         // --- IStoreListener
    190.         //
    191.  
    192.         public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    193.         {
    194.             Debug.Log("Unity IAP Manager OnInitialized: PASS");
    195.  
    196.             m_StoreController = controller;
    197.             m_StoreExtensionProvider = extensions;
    198.             StoreManager.Instance.UnityInitialized = true;
    199.         }
    200.  
    201.  
    202.         public void OnInitializeFailed(InitializationFailureReason error)
    203.         {
    204.             // Purchasing set-up has not succeeded. Check error for reason. Consider sharing this reason with the user.
    205.             Debug.Log("Unity IAP Manager OnInitializeFailed InitializationFailureReason:" + error);
    206.         }
    207.  
    208.  
    209.         public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
    210.         {
    211.             // Return a flag indicating whether this product has completely been received, or if the application needs
    212.             // to be reminded of this purchase at next app launch. Use PurchaseProcessingResult.Pending when still
    213.             // saving purchased products to the cloud, and when that save is delayed.
    214.  
    215.             StoreManager.Instance.CompletePurchaseItem(StoreManager.Instance.StoreItems.FirstOrDefault(i => ((StoreItemUnityIAP)i).ProductID == args.purchasedProduct.definition.id));
    216.        
    217.             return PurchaseProcessingResult.Complete;
    218.         }
    219.  
    220.  
    221.         public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
    222.         {
    223.             // A product purchase attempt did not succeed. Check failureReason for more detail. Consider sharing
    224.             // this reason with the user to guide their troubleshooting actions.
    225.             Debug.Log(string.Format("Unity IAP Manager OnPurchaseFailed: FAIL. Product: '{0}', PurchaseFailureReason: {1}", product.definition.storeSpecificId, failureReason));
    226.         }
    227.  
    228.     }
    229. }
    and my StoreItemUnityIAP.cs:

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Threading.Tasks;
    6.  
    7. namespace CoddlePets.DragonGarden
    8. {
    9.     public class StoreItemUnityIAP : StoreItem
    10.     {
    11.         public string GoogleProductID { get; set; }
    12.         public string AppleProductID { get; set; }
    13.  
    14.         public override void OnCompletePurchase()
    15.         {
    16.             throw new NotImplementedException();
    17.         }
    18.  
    19.         public override void OnStartPurchase()
    20.         {
    21.             StoreManager.Instance.UnityIAPManager.BuyConsumable(ProductID);
    22.         }
    23.         public override bool CanPurchase()
    24.         {
    25. #if UNITY_ANDROID || UNITY_IOS
    26.             return true;
    27. #else
    28.             return false;
    29. #endif
    30.         }
    31.     }
    32.  
    33.  
    34.     public class Nuggets10 : StoreItemUnityIAP
    35.     {
    36.         public int Nuggets = 10;
    37.         public Nuggets10()
    38.         {
    39.             GoogleProductID = "nuggets10";
    40.             AppleProductID = "nugget10";
    41.             ProductID = "nuggets10";
    42.         }
    43.  
    44.  
    45.         public override void OnCompletePurchase()
    46.         {
    47.             InventoryManager.Instance.AddNuggets(10, "10 Nuggets",
    48.                                OnComplete: (res) =>
    49.                                {
    50.                                    CaveDragonManager.Instance.ShowReceipt("10 Nuggets");
    51.                                }
    52.                                );
    53.         }
    54.     }
    55.  
    56.     public class Nuggets50 : StoreItemUnityIAP
    57.     {
    58.         public int Nuggets = 50;
    59.         public Nuggets50()
    60.         {
    61.             GoogleProductID = "nuggets50";
    62.             AppleProductID = "nugget50";
    63.             ProductID = "nuggets50";
    64.         }
    65.         public override void OnCompletePurchase()
    66.         {
    67.             InventoryManager.Instance.AddNuggets(50, "50 Nuggets",
    68.                                OnComplete: (res) =>
    69.                                {
    70.                                    CaveDragonManager.Instance.ShowReceipt("50 Nuggets");
    71.                                }
    72.                                );
    73.         }
    74.     }
    75.  
    76.     public class Nuggets100 : StoreItemUnityIAP
    77.     {
    78.         public int Nuggets = 100;
    79.         public Nuggets100()
    80.         {
    81.             GoogleProductID = "nuggets100";
    82.             AppleProductID = "nugget100";
    83.             ProductID = "nuggets100";
    84.         }
    85.         public override void OnCompletePurchase()
    86.         {
    87.             InventoryManager.Instance.AddNuggets(100, "100 Nuggets",
    88.                                OnComplete: (res) =>
    89.                                {
    90.                                    CaveDragonManager.Instance.ShowReceipt("100 Nuggets");
    91.                                }
    92.                                );
    93.         }
    94.     }
    95.  
    96.     public class Nuggets500 : StoreItemUnityIAP
    97.     {
    98.         public int Nuggets = 500;
    99.         public Nuggets500()
    100.         {
    101.             GoogleProductID = "nuggets500";
    102.             AppleProductID = "nugget500";
    103.             ProductID = "nuggets500";
    104.         }
    105.         public override void OnCompletePurchase()
    106.         {
    107.             InventoryManager.Instance.AddNuggets(500, "500 Nuggets",
    108.                                OnComplete: (res) =>
    109.                                {
    110.                                    CaveDragonManager.Instance.ShowReceipt("500 Nuggets");
    111.                                }
    112.                                );
    113.         }
    114.     }
    115.  
    116. }
    117.  
     

    Attached Files:

  2. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
  3. dcavadia

    dcavadia

    Joined:
    Aug 27, 2020
    Posts:
    15
    Ok i change the code to remove store specificIDs (now: builder.AddProduct(item.productID, item.productType)) but the error is still there...
    upload_2021-6-3_20-20-30.png

    I'm using Unity 2020.1.15f1 btw..
     
  4. dcavadia

    dcavadia

    Joined:
    Aug 27, 2020
    Posts:
    15
    i also noticed this warning in the Unity Cloud Log,
    "WARNING: missing .meta file: /BUILD_PATH/furuknap2.dragon-garden.dragon-garden-ios-release/Assets/Plugins/UnityPurchasing~"

    upload_2021-6-3_20-29-30.png

    but I don't know if it is relevant since is just a .meta (even though I don't have any folder inside Plugins).
     

    Attached Files:

  5. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Have you cleared all the issues on your Apple dashboard? The screenshot said "1 problem..." Also, be sure to be using IAP 3.2.0
     
  6. dcavadia

    dcavadia

    Joined:
    Aug 27, 2020
    Posts:
    15
    Well, actually they just gave me a general
    solution of using validation. But i dont even get to the part of initialization the IAP so i guess thats not the solution.

    upload_2021-6-4_9-52-37.png
     

    Attached Files:

  7. dcavadia

    dcavadia

    Joined:
    Aug 27, 2020
    Posts:
    15
    I have the IAP 3.2.1 though, inside Packages and without folder in Plugins
     
  8. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    I'm not referring to the review. I'm talking about the issue reported in your previous screenshot. 1 problema sin resolver, is that what you are referring to? And what version of IAP are you using. Please show your updated code.
     
  9. dcavadia

    dcavadia

    Joined:
    Aug 27, 2020
    Posts:
    15
    Yes, that 1 problema sin resolver is the one related to the IAP. upload_2021-6-4_10-43-16.png

    Im using IAP 3.2.1

    Here the UnityIAPManager.cs

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using System.Linq;
    3. using System.Reflection;
    4. using UnityEngine;
    5. using UnityEngine.Purchasing;
    6. using UnityEngine.Purchasing.Security;
    7. // Dragon Garden
    8.  
    9. namespace CoddlePets.DragonGarden
    10. {
    11.     public class UnityIAPProduct
    12.     {
    13.         public string productID;
    14.         public ProductType productType = ProductType.Consumable;
    15.         public IDs storeProductIDs;
    16.     }
    17.     // Deriving the Purchaser class from IStoreListener enables it to receive messages from Unity Purchasing.
    18.     public class UnityIAPManager : SingletonComponent<UnityIAPManager>, IStoreListener
    19.     {
    20.         private static IStoreController m_StoreController;          // The Unity Purchasing system.
    21.         private static IExtensionProvider m_StoreExtensionProvider; // The store-specific Purchasing subsystems.
    22.         private IAppleExtensions m_AppleExtensions;
    23.         private IGooglePlayStoreExtensions m_GoogleExtensions;
    24.  
    25.         List<UnityIAPProduct> Products = new List<UnityIAPProduct>();
    26.  
    27.         void Start()
    28.         {
    29.  
    30.             var types = Assembly.GetExecutingAssembly().GetTypes()
    31.                 .Where(t => t.IsSubclassOf(typeof(StoreItemUnityIAP)) && t.FullName != "CoddlePets.DragonGarden.StoreItem")
    32.  
    33.  
    34.                 .ToList();
    35.  
    36.             foreach (var type in types)
    37.             {
    38.                 var product = (StoreItemUnityIAP)Assembly.GetExecutingAssembly().CreateInstance(type.FullName);
    39.  
    40.                 var ids = new IDs { };
    41.                 if (!string.IsNullOrEmpty(product.GoogleProductID))
    42.                 {
    43.                     ids.Add(product.GoogleProductID, new string[] { GooglePlay.Name });
    44.                     Debug.Log("Android: " + product.GoogleProductID);
    45.  
    46.                 }
    47.                 if (!string.IsNullOrEmpty(product.AppleProductID))
    48.                 {
    49.                     ids.Add(product.AppleProductID, new string[] { AppleAppStore.Name });
    50.                     Debug.Log("iOS: " + product.AppleProductID);
    51.  
    52.                 }
    53.  
    54.                 AddProduct(product.ProductID, storeProductIDs: ids);
    55.                 StoreManager.Instance.StoreItems.Add(product);
    56.  
    57.                 Debug.Log("Added: " + product.ProductID);
    58.             }
    59.  
    60.             InitializePurchasing();
    61.  
    62.         }
    63.  
    64.         public void AddProduct(string productID, ProductType productType = ProductType.Consumable, IDs storeProductIDs = null)
    65.         {
    66.             if (!Products.Any(p => p.productID == productID))
    67.             {
    68.                 Products.Add(new UnityIAPProduct { productID = productID, productType = productType, storeProductIDs = storeProductIDs });
    69.             }
    70.         }
    71.  
    72.         public void InitializePurchasing()
    73.         {
    74.             // If we have already connected to Purchasing ...
    75.             if (IsInitialized())
    76.             {
    77.                 // ... we are done here.
    78.                 Debug.Log("Already INIT");
    79.                 return;
    80.             }
    81.  
    82.             // Create a builder, first passing in a suite of Unity provided stores.
    83.             var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
    84.  
    85.             // Add a product to sell / restore by way of its identifier, associating the general identifier
    86.             // with its store-specific identifiers.
    87.  
    88.             foreach (var item in Products)
    89.             {
    90.  
    91.                 /*if (item.storeProductIDs != null)
    92.                 {
    93.                     builder.AddProduct(item.productID, item.productType, item.storeProductIDs);
    94.                 }
    95.                 else
    96.                 {
    97.                     builder.AddProduct(item.productID, item.productType);
    98.                 }*/
    99.                 builder.AddProduct(item.productID, item.productType);
    100.             }
    101.  
    102.  
    103.             // Kick off the remainder of the set-up with an asynchrounous call, passing the configuration
    104.             // and this class' instance. Expect a response either in OnInitialized or OnInitializeFailed.
    105.             Debug.Log("Call init");
    106.             UnityPurchasing.Initialize(this, builder);
    107.         }
    108.  
    109.  
    110.         private bool IsInitialized()
    111.         {
    112.             // Only say we are initialized if both the Purchasing references are set.
    113.             return m_StoreController != null && m_StoreExtensionProvider != null;
    114.         }
    115.  
    116.  
    117.         public void BuyConsumable(string productId)
    118.         {
    119.             BuyProductID(productId);
    120.         }
    121.  
    122.  
    123.         private void BuyProductID(string productId)
    124.         {
    125.             if (IsInitialized())
    126.             {
    127.                 Product product = m_StoreController.products.WithID(productId);
    128.  
    129.                 if (product != null && product.availableToPurchase)
    130.                 {
    131.                     Debug.Log(string.Format("Purchasing product asychronously: '{0}'", product.definition.id));
    132.                     m_StoreController.InitiatePurchase(product);
    133.                 }
    134.                 // Otherwise ...
    135.                 else
    136.                 {
    137.                     // ... report the product look-up failure situation
    138.                     Debug.Log("Unity IAP Manager BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase");
    139.                 }
    140.             }
    141.             // Otherwise ...
    142.             else
    143.             {
    144.                 // ... report the fact Purchasing has not succeeded initializing yet. Consider waiting longer or
    145.                 // retrying initiailization.
    146.                 Debug.Log("Unity IAP Manager BuyProductID FAIL. Not initialized.");
    147.             }
    148.         }
    149.  
    150.  
    151.         // Restore purchases previously made by this customer. Some platforms automatically restore purchases, like Google.
    152.         // Apple currently requires explicit purchase restoration for IAP, conditionally displaying a password prompt.
    153.         public void RestorePurchases()
    154.         {
    155.             // If Purchasing has not yet been set up ...
    156.             if (!IsInitialized())
    157.             {
    158.                 // ... report the situation and stop restoring. Consider either waiting longer, or retrying initialization.
    159.                 Debug.Log("Unity IAP Manager RestorePurchases FAIL. Not initialized.");
    160.                 return;
    161.             }
    162.  
    163.             // If we are running on an Apple device ...
    164.             if (Application.platform == RuntimePlatform.IPhonePlayer ||
    165.                 Application.platform == RuntimePlatform.OSXPlayer)
    166.             {
    167.                 // ... begin restoring purchases
    168.                 Debug.Log("Unity IAP Manager RestorePurchases started ...");
    169.  
    170.                 // Fetch the Apple store-specific subsystem.
    171.                 var apple = m_StoreExtensionProvider.GetExtension<IAppleExtensions>();
    172.  
    173.                 // Begin the asynchronous process of restoring purchases. Expect a confirmation response in
    174.                 // the Action<bool> below, and ProcessPurchase if there are previously purchased products to restore.
    175.                 apple.RestoreTransactions((result) =>
    176.                 {
    177.                     // The first phase of restoration. If no more responses are received on ProcessPurchase then
    178.                     // no purchases are available to be restored.
    179.                     Debug.Log("Unity IAP Manager RestorePurchases continuing: " + result + ". If no further messages, no purchases available to restore.");
    180.                 });
    181.             }
    182.             // Otherwise ...
    183.             else
    184.             {
    185.                 // We are not running on an Apple device. No work is necessary to restore purchases.
    186.                 Debug.Log("Unity IAP Manager RestorePurchases FAIL. Not supported on this platform. Current = " + Application.platform);
    187.             }
    188.         }
    189.  
    190.  
    191.         //
    192.         // --- IStoreListener
    193.         //
    194.  
    195.         public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    196.         {
    197.             Debug.Log("Unity IAP Manager OnInitialized: PASS");
    198.  
    199.             m_StoreController = controller;
    200.             m_StoreExtensionProvider = extensions;
    201.             StoreManager.Instance.UnityInitialized = true;
    202.         }
    203.  
    204.  
    205.         public void OnInitializeFailed(InitializationFailureReason error)
    206.         {
    207.             // Purchasing set-up has not succeeded. Check error for reason. Consider sharing this reason with the user.
    208.             Debug.Log("Unity IAP Manager OnInitializeFailed InitializationFailureReason:" + error);
    209.         }
    210.  
    211.  
    212.         public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
    213.         {
    214.             // Return a flag indicating whether this product has completely been received, or if the application needs
    215.             // to be reminded of this purchase at next app launch. Use PurchaseProcessingResult.Pending when still
    216.             // saving purchased products to the cloud, and when that save is delayed.
    217.  
    218.             StoreManager.Instance.CompletePurchaseItem(StoreManager.Instance.StoreItems.FirstOrDefault(i => ((StoreItemUnityIAP)i).ProductID == args.purchasedProduct.definition.id));
    219.          
    220.             return PurchaseProcessingResult.Complete;
    221.         }
    222.  
    223.  
    224.         public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
    225.         {
    226.             // A product purchase attempt did not succeed. Check failureReason for more detail. Consider sharing
    227.             // this reason with the user to guide their troubleshooting actions.
    228.             Debug.Log(string.Format("Unity IAP Manager OnPurchaseFailed: FAIL. Product: '{0}', PurchaseFailureReason: {1}", product.definition.storeSpecificId, failureReason));
    229.         }
    230.  
    231.     }
    232. }
     
  10. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Have you changed your code so you are not using Store specific IDs, as a test? Please test with specifically with the Sample IAP Project. Don't just compare the code, actually publish the Sample project
     
  11. dcavadia

    dcavadia

    Joined:
    Aug 27, 2020
    Posts:
    15
    Code (CSharp):
    1. foreach (var item in Products)
    2.             {
    3.                 /*if (item.storeProductIDs != null)
    4.                 {
    5.                     builder.AddProduct(item.productID, item.productType, item.storeProductIDs);
    6.                 }
    7.                 else
    8.                 {
    9.                     builder.AddProduct(item.productID, item.productType);
    10.                 }*/
    11.                 builder.AddProduct(item.productID, item.productType);
    12.             }
    that part is where i removed the store specific ID.

    So i set up an scene with the sample you send me and modify its products to the ones in my apple setup?
     
  12. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    No, don't set up a new scene or add it to your game. Just use the scene in the Sample IAP Project in a whole new app, create a "noads" and "gold50" product, etc. Yes a bit of a pain, but now you'll have a project that you can use for testing new features without ever breaking your game. I find it better to iterate and build on success than chase bugs.
     
  13. dcavadia

    dcavadia

    Joined:
    Aug 27, 2020
    Posts:
    15
    Ok ill set that up but I wont be able to test it in iOS though, since the only way to get a build for me right now is through Unity Cloud Build
     
  14. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
  15. dcavadia

    dcavadia

    Joined:
    Aug 27, 2020
    Posts:
    15
    Then I need to add it to the build so I get the update in TestFlight, it's ok...I will add a button to start that scene and test it...
     
  16. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    No, I'm suggesting a new and separate project. Is there a reason that is not possible for you? Otherwise you'll need to replace all your IAP initialization logic, it shouldn't be per-scene but instead using a global singleton object or similar (like in the Sample project)
     
  17. dcavadia

    dcavadia

    Joined:
    Aug 27, 2020
    Posts:
    15
    Yes thats not possible since i dont have a Mac to get a build to my iOS, only through the Unity Cloud connected to the project
     
  18. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Yes, I understand. Just create a new Cloud Build project
     
  19. dcavadia

    dcavadia

    Joined:
    Aug 27, 2020
    Posts:
    15
    Ok, I'll let u know once I can test it. Thanks, Jeff
     
  20. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    You are most welcome. Once you get it added to TestFlight, feel free to send me a direct message here and I can provide my TestFlight email address. I'll take a look too.
     
  21. dcavadia

    dcavadia

    Joined:
    Aug 27, 2020
    Posts:
    15
    I just tested and still cant initialize it correctly upload_2021-6-4_18-47-6.png

    i added the scene to my project as a main scene, modified the MyIAPManager.cs to match my items
    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Purchasing;
    5. using UnityEngine.UI;
    6. using UnityEngine.Purchasing.Security;
    7.  
    8.  
    9. public class MyIAPManager : MonoBehaviour, IStoreListener
    10. {
    11.     private static IStoreController m_StoreController;          // The Unity Purchasing system.
    12.     private static IExtensionProvider m_StoreExtensionProvider; // The store-specific Purchasing subsystems.
    13.     private IAppleExtensions m_AppleExtensions;
    14.     private IGooglePlayStoreExtensions m_GoogleExtensions;
    15.  
    16.     // ProductIDs
    17.     public static string NUGGET_10 = "nugget10";
    18.     public static string NUGGET_50 = "nugget50";
    19.     public static string NUGGET_100 = "nugget100";
    20.     public static string NUGGET_500 = "nugget500";
    21.     public static string NONCONSUMABLE1 = "nonconsume1";
    22.     public static string WEEKLYSUB = "weeklysub";
    23.  
    24.     public Text myText;
    25.  
    26.     void Awake()
    27.     {
    28.  
    29.     }
    30.  
    31.  
    32.     void Start()
    33.     {
    34.         // If we haven't set up the Unity Purchasing reference
    35.         if (m_StoreController == null)
    36.         {
    37.             // Begin to configure our connection to Purchasing, can use button click instead
    38.             //InitializePurchasing();
    39.         }
    40.     }
    41.  
    42.     public void MyInitialize()
    43.     {
    44.         InitializePurchasing();
    45.     }
    46.  
    47.     public void InitializePurchasing()
    48.     {
    49.         if (IsInitialized())
    50.         {
    51.             return;
    52.         }
    53.  
    54.         var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
    55.  
    56.         builder.AddProduct(NONCONSUMABLE1, ProductType.NonConsumable);
    57.         builder.AddProduct(NUGGET_10, ProductType.Consumable);
    58.         builder.AddProduct(NUGGET_50, ProductType.Consumable);
    59.         builder.AddProduct(NUGGET_100, ProductType.Consumable);
    60.         builder.AddProduct(NUGGET_500, ProductType.Consumable);
    61.         builder.AddProduct(WEEKLYSUB, ProductType.Subscription);
    62.  
    63.         MyDebug("Starting Initialized...");
    64.         UnityPurchasing.Initialize(this, builder);
    65.  
    66.     }
    67.  
    68.  
    69.     private bool IsInitialized()
    70.     {
    71.         return m_StoreController != null && m_StoreExtensionProvider != null;
    72.     }
    73.  
    74.     public void BuySubscription()
    75.     {
    76.         BuyProductID(WEEKLYSUB);
    77.     }
    78.  
    79.  
    80.     public void BuyNugget10 ()
    81.     {
    82.         BuyProductID(NUGGET_10);
    83.     }
    84.  
    85.     public void BuyNonConsumable()
    86.     {
    87.         BuyProductID(NONCONSUMABLE1);
    88.     }
    89.    
    90.     public void RestorePurchases()
    91.     {
    92.         m_StoreExtensionProvider.GetExtension<IAppleExtensions>().RestoreTransactions(result => {
    93.             if (result)
    94.             {
    95.                 MyDebug("Restore purchases succeeded.");
    96.             }
    97.             else
    98.             {
    99.                 MyDebug("Restore purchases failed.");
    100.             }
    101.          });
    102.     }
    103.  
    104.     void BuyProductID(string productId)
    105.     {
    106.         if (IsInitialized())
    107.         {
    108.             UnityEngine.Purchasing.Product product = m_StoreController.products.WithID(productId);
    109.  
    110.             if (product != null && product.availableToPurchase)
    111.             {
    112.                 MyDebug(string.Format("Purchasing product:" + product.definition.id.ToString()));
    113.                 m_StoreController.InitiatePurchase(product);
    114.             }
    115.             else
    116.             {
    117.                 MyDebug("BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase");
    118.             }
    119.         }
    120.         else
    121.         {
    122.             MyDebug("BuyProductID FAIL. Not initialized.");
    123.         }
    124.     }
    125.  
    126.     public void ListProducts()
    127.     {
    128.  
    129.         foreach (UnityEngine.Purchasing.Product item in m_StoreController.products.all)
    130.         {
    131.             if (item.receipt != null)
    132.             {
    133.                 MyDebug("Receipt found for Product = " + item.definition.id.ToString());
    134.             }
    135.         }
    136.     }
    137.     public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    138.     {
    139.         MyDebug("OnInitialized: PASS");
    140.  
    141.         m_StoreController = controller;
    142.         m_StoreExtensionProvider = extensions;
    143.         m_AppleExtensions = extensions.GetExtension<IAppleExtensions>();
    144.         m_GoogleExtensions = extensions.GetExtension<IGooglePlayStoreExtensions>();
    145.  
    146.         m_GoogleExtensions?.SetDeferredPurchaseListener(OnPurchaseDeferred);
    147.  
    148.         Dictionary<string, string> dict = m_AppleExtensions.GetIntroductoryPriceDictionary();
    149.  
    150.         foreach (UnityEngine.Purchasing.Product item in controller.products.all)
    151.         {
    152.  
    153.             if (item.receipt != null)
    154.             {
    155.                 string intro_json = (dict == null || !dict.ContainsKey(item.definition.storeSpecificId)) ? null : dict[item.definition.storeSpecificId];
    156.  
    157.                 if (item.definition.type == ProductType.Subscription)
    158.                 {
    159.                     SubscriptionManager p = new SubscriptionManager(item, intro_json);
    160.                     SubscriptionInfo info = p.getSubscriptionInfo();
    161.                     MyDebug("SubInfo: " + info.getProductId().ToString());
    162.                     MyDebug("isSubscribed: " + info.isSubscribed().ToString());
    163.                     MyDebug("isFreeTrial: " + info.isFreeTrial().ToString());
    164.                 }
    165.             }
    166.         }
    167.     }
    168.  
    169.     public void OnPurchaseDeferred(Product product)
    170.     {
    171.  
    172.         MyDebug("Deferred product " + product.definition.id.ToString());
    173.     }
    174.  
    175.     public void OnInitializeFailed(InitializationFailureReason error)
    176.     {
    177.         // Purchasing set-up has not succeeded. Check error for reason. Consider sharing this reason with the user.
    178.         MyDebug("OnInitializeFailed InitializationFailureReason:" + error);
    179.     }
    180.  
    181.  
    182.     public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
    183.     {
    184.  
    185.        /* try
    186.         {
    187.             var validator = new CrossPlatformValidator(GooglePlayTangle.Data(), AppleTangle.Data(), Application.identifier);
    188.             var result = validator.Validate(args.purchasedProduct.receipt);
    189.             MyDebug("Validate = " + result.ToString());
    190.  
    191.             foreach (IPurchaseReceipt productReceipt in result)
    192.             {
    193.                 MyDebug("Valid receipt for " + productReceipt.productID.ToString());
    194.             }
    195.         }
    196.         catch (Exception e)
    197.         {
    198.             MyDebug("Error is " + e.Message.ToString());
    199.         }
    200.        */
    201.         MyDebug(string.Format("ProcessPurchase: " + args.purchasedProduct.definition.id));
    202.  
    203.         return PurchaseProcessingResult.Complete;
    204.      
    205.      }
    206.  
    207.  
    208.     public void OnPurchaseFailed(UnityEngine.Purchasing.Product product, PurchaseFailureReason failureReason)
    209.     {
    210.         MyDebug(string.Format("OnPurchaseFailed: FAIL. Product: '{0}', PurchaseFailureReason: {1}", product.definition.storeSpecificId, failureReason));
    211.     }
    212.  
    213.  
    214.     private void MyDebug(string debug)
    215.     {
    216.        
    217.         Debug.Log(debug);
    218.         myText.text += "\r\n" + debug;
    219.     }
    220.  
    221. }
    222.  
    i dont know what else it could be... i appreciate the help!
     
  22. dcavadia

    dcavadia

    Joined:
    Aug 27, 2020
    Posts:
    15
    it may be relevant, but after clicking Initialize, it takes about 3s and then trow the error
     
  23. dcavadia

    dcavadia

    Joined:
    Aug 27, 2020
    Posts:
    15
    upload_2021-6-4_18-56-5.png
    some insight to the ios build...

    i still believe it may be something related to the config
     
  24. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    You are not following my instructions. I specifically stated to create a NEW Cloud Build project. Do not add the scene to your existing project. Please simplify the problem as suggested. Create the products noads and gold50.
     
  25. dcavadia

    dcavadia

    Joined:
    Aug 27, 2020
    Posts:
    15
    I don't think I can create a NEW Cloud Build project since I don't have enough permission to do that in the organization besides the iTunes connect with the Testflight organization being owned by the client... Meanwhile in getting macOS in a VM to make build locally to my iPhone... i thinks that's the only way for me to follow your instructions
     
  26. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Generally you need an Apple developer account and a Mac to develop and debug apps for iOS.
     
  27. ritesh_khokhani

    ritesh_khokhani

    Joined:
    Jun 26, 2013
    Posts:
    47
    mismatching product IDs, that's all :)
     
  28. GuirieSanchez

    GuirieSanchez

    Joined:
    Oct 12, 2021
    Posts:
    387
    Where did you see that mismatch?
     
  29. eagleknight42

    eagleknight42

    Joined:
    Oct 23, 2021
    Posts:
    24
    I got the same problem
     
  30. Arnaud_Gorain

    Arnaud_Gorain

    Unity Technologies

    Joined:
    Jun 28, 2022
    Posts:
    170
    Hi @GuirieSanchez @rocketshader,
    The mismatch here is the naming of the product id that is defined on the Google/Apple and the naming used in the game code that were different. Once a product is named on the stores, it must be used with the exact same name in your game code.
    Hope it helps!
     
    GuirieSanchez likes this.
  31. eagleknight42

    eagleknight42

    Joined:
    Oct 23, 2021
    Posts:
    24
    Does IAP UI shows on phones when I upload a build to google play store? Do you know that? I mean the operating system UI that shows to buy the product. I guess so but ım not sure, thanks.