OnInitializeFailed InitializationFailureReason:NoProductsAvailable

Hello.
I don’t really know what to do and how to fix this. This is my first time implementing IAP, I used this tutorial

to set this up.
My Code:

manager:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Purchasing;
public class IAPManager : Singleton<IAPManager>, IStoreListener
{
   
    private static IStoreController m_StoreController;          // The Unity Purchasing system.
    private static IExtensionProvider m_StoreExtensionProvider; // The store-specific Purchasing subsystems.

 
    public string GetKey = "getkey";
    public string No_ADS = "no_ads";
  

    void Start()
    {
       
        if (m_StoreController == null)
        {
           
            InitializePurchasing();
        }
    }

    public void InitializePurchasing()
    {
       
        if (IsInitialized())
        {
           
            return;
        }

      
        var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());

     
        builder.AddProduct(GetKey, ProductType.Consumable);
      
        builder.AddProduct(No_ADS, ProductType.NonConsumable);
  
     
        UnityPurchasing.Initialize(this, builder);
    }


    public bool IsInitialized()
    {
      
        return m_StoreController != null && m_StoreExtensionProvider != null;
    }


    public void BuyKey()
    {
     
        BuyProductID(GetKey);
    }


    public void BuyNo_ADS()
    {
    
        BuyProductID(No_ADS);
    }

    public string GetProductPriceFromStore(string id)
    {
        if (m_StoreController != null && m_StoreController.products != null)
            return m_StoreController.products.WithID(id).metadata.localizedPriceString;
        else
            return "";
    }


    void BuyProductID(string productId)
    {
     
        if (IsInitialized())
        {
           
          
            Product product = m_StoreController.products.WithID(productId);

          
            if (product != null && product.availableToPurchase)
            {
                Debug.Log(string.Format("Purchasing product asychronously: '{0}'", product.definition.id));
           
                m_StoreController.InitiatePurchase(product);
            }
            // Otherwise ...
            else
            {
          
                Debug.Log("BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase");
            }
        }

        else
        {
          
            Debug.Log("BuyProductID FAIL. Not initialized.");
        }
    }


 



    //
    // --- IStoreListener
    //

    public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    {
        // Purchasing has succeeded initializing. Collect our Purchasing references.
        Debug.Log("OnInitialized: PASS");

        // Overall Purchasing system, configured with products for this application.
        m_StoreController = controller;
        // Store specific subsystem, for accessing device-specific store features.
        m_StoreExtensionProvider = extensions;
    }


    public void OnInitializeFailed(InitializationFailureReason error)
    {
        // Purchasing set-up has not succeeded. Check error for reason. Consider sharing this reason with the user.
        Debug.Log("OnInitializeFailed InitializationFailureReason:" + error);
    }


    public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
    {
        // A consumable product has been purchased by this user.
        if (String.Equals(args.purchasedProduct.definition.id, GetKey, StringComparison.Ordinal))
        {
            Debug.Log(string.Format("ProcessPurchase: PASS. Product: '{0}'", args.purchasedProduct.definition.id));
            // The consumable item has been successfully purchased, add 100 coins to the player's in-game score.
            GameManager.Instance.StoreGetKey();
        }
        // Or ... a non-consumable product has been purchased by this user.
        else if (String.Equals(args.purchasedProduct.definition.id, No_ADS, StringComparison.Ordinal))
        {
            Debug.Log(string.Format("ProcessPurchase: PASS. Product: '{0}'", args.purchasedProduct.definition.id));
            GameManager.Instance.StoreNoAds();
        }
        // Or ... a subscription product has been purchased by this user.
    
        // Or ... an unknown product has been purchased by this user. Fill in additional products here....
        else
        {
            Debug.Log(string.Format("ProcessPurchase: FAIL. Unrecognized product: '{0}'", args.purchasedProduct.definition.id));
        }

        // Return a flag indicating whether this product has completely been received, or if the application needs
        // to be reminded of this purchase at next app launch. Use PurchaseProcessingResult.Pending when still
        // saving purchased products to the cloud, and when that save is delayed.
        return PurchaseProcessingResult.Complete;
    }


    public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
    {
        // A product purchase attempt did not succeed. Check failureReason for more detail. Consider sharing
        // this reason with the user to guide their troubleshooting actions.
        Debug.Log(string.Format("OnPurchaseFailed: FAIL. Product: '{0}', PurchaseFailureReason: {1}", product.definition.storeSpecificId, failureReason));
    }
}

and here is script on store buttons:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class StoreButton : MonoBehaviour
{
    public enum ItemType
    {
        GetKey,
        NoAds
    }

    public ItemType itemType;
    public TextMeshProUGUI priceText;
    private string defaultText;

  
    void Start()
    {
        defaultText = priceText.text;
        StartCoroutine(LoadPriceRoutine());
    }

    public void ClickBuy()
    {
        switch (itemType)
        {
            case ItemType.GetKey:
                IAPManager.Instance.BuyKey();
                break;
            case ItemType.NoAds:
                IAPManager.Instance.BuyNo_ADS();
                break;
        }
    }

    private IEnumerator LoadPriceRoutine()
    {
        while (!IAPManager.Instance.IsInitialized())
            yield return null;
        string loadedPrice = "";
        switch (itemType)
        {
            case ItemType.GetKey:
                loadedPrice = IAPManager.Instance.GetProductPriceFromStore(IAPManager.Instance.GetKey);
                break;
            case ItemType.NoAds:
                loadedPrice = IAPManager.Instance.GetProductPriceFromStore(IAPManager.Instance.No_ADS);
                break;
        }

        priceText.text = defaultText + "" + loadedPrice;
    }

 
}
  • Product IDs match with those from script.
  • I waited 24h
  • first check on dev acc, than check on tester acc, both same results in logcat
  • ofc everything works in editor
  • unity dashboard see that there are IAP set on google dev console with correct names.(edit - dashboard have under Platform column “Windows editor” so I guess it’s not recognized.
  • tested on real devices, 3 phones and 1 tablet
    edit:
  • I added product ID’s to the Unity dashboard under Monetization - In-app purchases, I don’t know I should do it but it’s only idea I’ve got so far.
  • Unity version - 2018.3.11f1
  • UnityIAP ver 1.22.0

I don’t really know where to start and what can I do now.
Please help.

edit.
btw. why all knowleage base and tutorials screenshots comes from old version of google dev console? Is it really that hard to update them to the current look? I know, everything is “findable” but implementing everything in Google Console is already very confusing so making it even more not-clear isn’t help anyone.

5011136–490175–logcat.txt (5.65 KB)

Except for the good luck comment, you need to define your products on the Google Developer dashboard. This link is a bit outdated, but should get you started. Unity - Manual: Configuring for Google Play Store

Ok, didnt said that… Ofcourse I did it. Second part of the tutorial I posted I did too… Everything is set up from google dev console side.
(Oh noooo… And again I will have to wait for reply 2 days :frowning: )

So like Wednesday? Got it! :slight_smile:

So in the meantime while you’re waiting, please provide a screenshot of your products defined on Google Play. The error says can’t find product GetKey, but you have it defined as getkey in your code.

I hope polish language isn’t a problem for you :wink:

Why are you requesting GetKey and not getkey? See the logs. Also, I might politely suggest, sarcasm is not in your best interest when someone is trying to help you. Regarding your 2 day comment, I generally don’t watch the forums on my days off.

Do you mean my code should look like this?

public string getkey = "getkey";

or I should change name of the request in google dev console?

Ok, I will not use sarcasm anymore. :wink:

No, you need to find out why your program is calling as GetKey and not getkey. Your method signature is as follows:

 public void BuyKey()
    {
    
        BuyProductID(GetKey);
    }

You are passing a global variable to a method. I would not do that. Use Debug.Log to confirm the string you are actually sending.

What you mean by “I would not do that” ? This script is copied from here Unity IAP - Unity Learn and look exactly the same.
And maybe it’s a lame question but how I should “use” Debug.log to confirm the string I’m sending ?

I can’t comment on the tutorial video. But I would suggest

void BuyProductID(string productId)
{
  Debug.Log ("My product is " + productId.ToString());
...

This will show in the device logs, or in the Unity Console. But you’ll want to test on a device, and capture the device logs. Debug.Log will show in the logs. How To - Capturing Device Logs on Android

Why you can’t comment on the tutorial video? If it’s bad, and I shouldn’t use it maybe it’s better to get rid of this scripts and just create a proper one? I don’t have programistic background so my code are mostly copy-paste and in most cases I can handle problems but if Unity or Google services are in play I don’t really know what I’m doing.
(I was sure this tutorial will be good - it’s a new wave - robotic hindi - just can’t be bad)

I simply meant that I can’t comment because I didn’t write it, was my point. Please follow my suggestions, and provide the output of Debug.Log. It is likely just a small syntax error in your C# code.

Ok, did what you said… I hope it is not a problem that I upload it as internal test (alpha test is like 12h waiting these days) and use my account.

5016617–491141–Logcat1.txt (17.9 KB)

You have other problems, note “NullReferenceException: Object reference not set to an instance of an object.” So you are not initializing, and there is a null object in your code that you’ll need to find via Debug.Log. Please show the code now that you’ve added the additional Debug.Log statement, and where you see it in the logs. And there is no “My product is…” in the logs, so that part of the code never executed.

I add to the script that store button is disabled on initialization failed… hmm… I didn’t test it because its always pass initialization in editor

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Purchasing;
public class IAPManager : Singleton<IAPManager>, IStoreListener
{
    
    private static IStoreController m_StoreController;          // The Unity Purchasing system.
    private static IExtensionProvider m_StoreExtensionProvider; // The store-specific Purchasing subsystems.


    public string GetKey = "getkey";
    public string No_ADS = "no_ads";
   

    void Start()
    {
        
        if (m_StoreController == null)
        {
           
            InitializePurchasing();
        }
    }

    public void InitializePurchasing()
    {
        
        if (IsInitialized())
        {
           
            return;
        }

       
        var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());

     
        builder.AddProduct(GetKey, ProductType.Consumable);
      
        builder.AddProduct(No_ADS, ProductType.NonConsumable);
   
        
        UnityPurchasing.Initialize(this, builder);
    }


    public bool IsInitialized()
    {
        
        return m_StoreController != null && m_StoreExtensionProvider != null;
    }


    public void BuyKey()
    {
      
        BuyProductID(GetKey);
    }


    public void BuyNo_ADS()
    {
       
        BuyProductID(No_ADS);
    }

    public string GetProductPriceFromStore(string id)
    {
        if (m_StoreController != null && m_StoreController.products != null)
            return m_StoreController.products.WithID(id).metadata.localizedPriceString;
        else
            return "";
    }


    void BuyProductID(string productId)
    {
        Debug.Log("My product is " + productId.ToString());
    
        if (IsInitialized())
        {
       
            Product product = m_StoreController.products.WithID(productId);

           
            if (product != null && product.availableToPurchase)
            {
                Debug.Log(string.Format("Purchasing product asychronously: '{0}'", product.definition.id));
           
                m_StoreController.InitiatePurchase(product);
            }
            // Otherwise ...
            else
            {
               
                Debug.Log("BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase");
            }
        }
      
        else
        {
      
            Debug.Log("BuyProductID FAIL. Not initialized.");
        }
    }


  



 
    public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    {
  
        Debug.Log("OnInitialized: PASS");

       
        m_StoreController = controller;
      
        m_StoreExtensionProvider = extensions;
    }


    public void OnInitializeFailed(InitializationFailureReason error)
    {
        
        Debug.Log("OnInitializeFailed InitializationFailureReason:" + error);
        MenuScript.Instance.StoreButton.SetActive(false);
    }


    public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
    {
       
        if (String.Equals(args.purchasedProduct.definition.id, GetKey, StringComparison.Ordinal))
        {
            Debug.Log(string.Format("ProcessPurchase: PASS. Product: '{0}'", args.purchasedProduct.definition.id));
       
            GameManager.Instance.StoreGetKey();
        }
     
        else if (String.Equals(args.purchasedProduct.definition.id, No_ADS, StringComparison.Ordinal))
        {
            Debug.Log(string.Format("ProcessPurchase: PASS. Product: '{0}'", args.purchasedProduct.definition.id));
            GameManager.Instance.StoreNoAds();
        }
      
        else
        {
            Debug.Log(string.Format("ProcessPurchase: FAIL. Unrecognized product: '{0}'", args.purchasedProduct.definition.id));
        }

    
        return PurchaseProcessingResult.Complete;
    }


    public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
    {

        Debug.Log(string.Format("OnPurchaseFailed: FAIL. Product: '{0}', PurchaseFailureReason: {1}", product.definition.storeSpecificId, failureReason));
    }
}

You might also consider the Sample IAP projects (that I DID write!) here Sample IAP Project

Yes, we use a fake store in the Editor that always initializes successfully (as long as there are no errors in your code)

there is “My product is…”
(Filename: ./Runtime/Export/Debug.bindings.h Line: 45)
09-30 20:50:40.974 25377-25398/? I/Unity: My product is GetKey
IAPManager:BuyProductID(String)
UnityEngine.Events.UnityEvent:Invoke()
UnityEngine.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1)
UnityEngine.EventSystems.StandaloneInputModule:ProcessTouchPress(PointerEventData, Boolean, Boolean)
UnityEngine.EventSystems.StandaloneInputModule:ProcessTouchEvents()
UnityEngine.EventSystems.StandaloneInputModule:Process()

(Filename: ./Runtime/Export/Debug.bindings.h Line: 45)
09-30 20:50:40.985 25377-25398/? I/Unity: BuyProductID FAIL. Not initialized.
UnityEngine.Events.UnityEvent:Invoke()
UnityEngine.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1)
UnityEngine.EventSystems.StandaloneInputModule:ProcessTouchPress(PointerEventData, Boolean, Boolean)
UnityEngine.EventSystems.StandaloneInputModule:ProcessTouchEvents()
UnityEngine.EventSystems.StandaloneInputModule:Process()

There you go. Your product is named getkey and not GetKey. I see two possible solutions, one to fix your code, and other to simply change the product name on the Google Dashboard (which I would not advise as it would only mask your bug)