Seeking help with In-App purchase.

Hi all,

I am having an issue with In-app purchase v4.12 (also with previous versions). It works on 2 android devices that I have (internal test and production) but usually have crashes reported from Firebase.

Cash detail:

Fatal Exception: java.lang.Exception: NullReferenceException : Object reference not set to an instance of an object.
at IAPManager.DiamondPurchase(IAPManager)
at ShopManager.yesButtonClicked(ShopManager)
at UnityEngine.Events.UnityEvent.Invoke(UnityEngine.Events.UnityEvent)
at UnityEngine.EventSystems.ExecuteEvents.ExecuteT
at UnityEngine.EventSystems.StandaloneInputModule.ProcessTouchPress(UnityEngine.EventSystems.StandaloneInputModule)
at UnityEngine.EventSystems.StandaloneInputModule.ProcessTouchEvents(UnityEngine.EventSystems.StandaloneInputModule)
at UnityEngine.EventSystems.StandaloneInputModule.Process(UnityEngine.EventSystems.StandaloneInputModule)
at UnityEngine.EventSystems.StandaloneInputModule:Process(UnityEngine.EventSystems)

I used product IDs on google play console, and pretty sure that all product IDs works.

First I initiated the unity game service, I am not sure if I need this since I used the product ID on google play console. I added this lately when trying to avoid the crash and remove a warning on unity console:

using System;
using Unity.Services.Core;
using Unity.Services.Core.Environments;
using UnityEngine;
using TMPro;

public class InitializeUnityGameServices : MonoBehaviour
{
    [SerializeField] TextMeshProUGUI informationText;

    const string k_Environment = "production";

    void Awake(){
        // Uncomment this line to initialize Unity Gaming Services.
        Initialize(OnSuccess, OnError);
    }

    void Initialize(Action onSuccess, Action<string> onError){
        try{
            var options = new InitializationOptions().SetEnvironmentName(k_Environment);

            UnityServices.InitializeAsync(options).ContinueWith(task => onSuccess());
        }
        catch (Exception exception){
            onError(exception.Message);
        }
    }

    void OnSuccess(){
        var text = "USG";
        informationText.text = text;
        Debug.Log(text);
    }

    void OnError(string message){
        var text = $"FUSG {message}.";
        informationText.text = text;
        Debug.LogError(text);
    }

    void Start(){
        if (UnityServices.State == ServicesInitializationState.Uninitialized){
            var text =
                "Error: Unity Gaming Services not initialized.\n";
            informationText.text = text;
        }
    }
}

Here is the script to handle the purchase:

using UnityEngine.Purchasing;
using UnityEngine;
using UnityEngine.Purchasing.Extension;
using TMPro;
using GoogleMobileAds.Sample;  // spacename refine in GoogleMobileAdsController.cs

public class IAPManager : MonoBehaviour, IDetailedStoreListener
{
    public static IAPManager instance;
   
    IStoreController m_StoreController;
    [SerializeField] DiamondShopData diamondShopData;
    [SerializeField] InterstitialAdData adData;
    [SerializeField] GameObject noAdLevelPanel;

    [SerializeField] TextMeshProUGUI informationText;
    private int diamondIndex;
   
    void Awake(){
        if (instance == null)
            instance = this;
    }

    void Start(){
        SetupBuilder();
    }
   
    public void DiamondPurchase(int index){
        m_StoreController.InitiatePurchase(diamondShopData.iapID[index]);
    }

    public void NoAdPurchaseDollar(){
        m_StoreController.InitiatePurchase(adData.iapNoAdID);
    }

    private void SetupBuilder(){
        var buider = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
        buider.AddProduct(diamondShopData.iapID[0], ProductType.Consumable);
        buider.AddProduct(diamondShopData.iapID[1], ProductType.Consumable);
        buider.AddProduct(diamondShopData.iapID[2], ProductType.Consumable);
        buider.AddProduct(diamondShopData.iapID[3], ProductType.Consumable);
        buider.AddProduct(diamondShopData.iapID[4], ProductType.Consumable);

        buider.AddProduct(adData.iapNoAdID, ProductType.NonConsumable);
        UnityPurchasing.Initialize(this, buider);
    }

    public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    {
        // throw new System.NotImplementedException();
        // print("Successfully initialize IStoreController");
        informationText.text = "IAP";
        m_StoreController = controller;
    }

    public void OnInitializeFailed(InitializationFailureReason error)
    {
        // throw new System.NotImplementedException();
        // NotificationManager.instance.NotifyText("Initialize Failed " + error);
        FirebaseSetup.instance.LogIAPInitilizerError(error: error.ToString());
    }

    public void OnInitializeFailed(InitializationFailureReason error, string message)
    {
        // throw new System.NotImplementedException();
        // NotificationManager.instance.NotifyText("Initialize Failed " + error + message);
        FirebaseSetup.instance.LogIAPInitilizerErrorMessage(message: message.ToString());
    }

    public void OnPurchaseFailed(Product product, PurchaseFailureDescription failureDescription)
    {
        // throw new System.NotImplementedException();
        NotificationManager.instance.NotifyText("Purchase Failed");
        ShopManager.instance.enableAllButtons();
        FirebaseSetup.instance.LogEventPurchaseFailed(error: failureDescription.ToString());
    }

    public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
    {
        // throw new System.NotImplementedException();
        NotificationManager.instance.NotifyText("Purchase Failed");
        ShopManager.instance.enableAllButtons();
        FirebaseSetup.instance.LogEventPurchaseFailedIndex(index: diamondIndex);
    }

    public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent)
    {
        // throw new System.NotImplementedException();
        var product = purchaseEvent.purchasedProduct;
        // print("Purchase Complete" + product.definition.id);
        if (product.definition.id == diamondShopData.iapID[0]){
            ShopManager.instance.playerData.gameDiamonds += diamondShopData.DiamondPrice[0];
            ShopManager.instance.UpdateCurrency(diamondShopData.DiamondPrice[0], "Diamond");
            diamondIndex = 0;
        } else if (product.definition.id == diamondShopData.iapID[1]){
            ShopManager.instance.playerData.gameDiamonds += diamondShopData.DiamondPrice[1];
            ShopManager.instance.UpdateCurrency(diamondShopData.DiamondPrice[1], "Diamond");
            diamondIndex = 1;
        } else if (product.definition.id == diamondShopData.iapID[2]){
            ShopManager.instance.playerData.gameDiamonds += diamondShopData.DiamondPrice[2];
            ShopManager.instance.UpdateCurrency(diamondShopData.DiamondPrice[2], "Diamond");
            diamondIndex = 2;
        } else if (product.definition.id == diamondShopData.iapID[3]){
            ShopManager.instance.playerData.gameDiamonds += diamondShopData.DiamondPrice[3];
            ShopManager.instance.UpdateCurrency(diamondShopData.DiamondPrice[3], "Diamond");
            diamondIndex = 3;
        } else if (product.definition.id == diamondShopData.iapID[4]){
            ShopManager.instance.playerData.gameDiamonds += diamondShopData.DiamondPrice[4];
            ShopManager.instance.UpdateCurrency(diamondShopData.DiamondPrice[4], "Diamond");
            diamondIndex = 4;
        } else if (product.definition.id == adData.iapNoAdID){
            ShopManager.instance.playerData.gameCoins += adData.coinNoAd;
            ShopManager.instance.playerData.gameDiamonds += adData.diamondNoAd;
            ShopManager.instance.playerData.removeAds = 1;
            ActManager.instance.DisplayUIPanelOnLevelCanvas();
            BannerViewController.instance.HideAd();
            noAdLevelPanel.SetActive(false);
            diamondIndex = 5;
        }

        AudioManager.instance.PlaySound("shopBuy");
        PlayerDataManager.instance.SavePlayerAndActData();
        return PurchaseProcessingResult.Complete;
    }
}

I appreciate for any help. Thanks