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