Ill look into getting the logs to work but i have my custom debug log working in game and can see what the ‘console’ is printing. It passes the initializing. When i go to purchase the product, it comes up with this error:
OnPurchaseFailed: FAIL. Product ‘tokens10’, PurchaseFailureReason: Unknown
the game though in test acts like the purchases go through but the product isnt given to the player
This is my code:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Purchasing;
using UnityEngine.Events;
using UnityEngine.UI;
using GameAnalyticsSDK;
using CodeStage.AntiCheat.ObscuredTypes;
using UnityEngine.Purchasing.Security;
using I2.Loc;
public class Receipt
{
public string Store;
public string TransactionID;
public string Payload;
public Receipt()
{
Store = TransactionID = Payload = "";
}
public Receipt(string store, string transactionID, string payload)
{
Store = store;
TransactionID = transactionID;
Payload = payload;
}
}
public class PayloadAndroid
{
public string json;
public string signature;
public PayloadAndroid()
{
json = signature = "";
}
public PayloadAndroid(string _json, string _signature)
{
json = _json;
signature = _signature;
}
}
// Placing the Purchaser class in the CompleteProject namespace allows it to interact with ScoreManager,
// one of the existing Survival Shooter scripts.
// Deriving the Purchaser class from IStoreListener enables it to receive messages from Unity Purchasing.
public class InAppPurchasing : MonoBehaviour, IStoreListener
{
public static InAppPurchasing instance;
private static IStoreController m_StoreController;
// The Unity Purchasing system.
private static IExtensionProvider m_StoreExtensionProvider;
// The store-specific Purchasing subsystems.
public static string tokens1 = "tokens1";
public static string tokens5 = "tokens5";
public static string tokens10 = "tokens10";
public static string caps1000 = "1000caps";
public static string caps2000 = "2000caps";
public static string caps4000 = "4000caps";
public static string crate = "crate";
public static string ultimate_wanderer = "ultimate_wanderer";
public static string starterpack = "starterpack";
public static string weaponpack = "weaponpack";
public static string van = "van";
public static string scavengerMaterial = "scavengermaterial";
public static string remove_banner = "remove_banner";
public static string max_bag = "max_bag";
public static string subscription = "wanderer_subscription";
public static string infinitevan = "vanwarranty";
// Product identifiers for all products capable of being purchased:
// "convenience" general identifiers for use with Purchasing, and their store-specific identifier
// counterparts for use with and outside of Unity Purchasing. Define store-specific identifiers
// also on each platform's publisher dashboard (iTunes Connect, Google Play Developer Console, etc.)
// General product identifiers for the consumable, non-consumable, and subscription products.
// Use these handles in the code to reference which product to purchase. Also use these values
// when defining the Product Identifiers on the store. Except, for illustration purposes, the
// kProductIDSubscription - it has custom Apple and Google identifiers. We declare their store-
// specific mapping to Unity Purchasing's AddProduct, below.
public static string kProductIDConsumable = "consumable";
public static string kProductIDNonConsumable = "nonconsumable";
public static string kProductIDSubscription = "subscription";
// Apple App Store-specific product identifier for the subscription product.
private static string kProductNameAppleSubscription = "com.unity3d.subscription.new";
// Google Play Store-specific product identifier subscription product.
private static string kProductNameGooglePlaySubscription = "com.unity3d.subscription.original";
void Start()
{
instance = this;
// If we haven't set up the Unity Purchasing reference
if (m_StoreController == null)
{
// Begin to configure our connection to Purchasing
InitializePurchasing();
}
#if UNITY_IOS
RestorePurchases();
#endif
}
public bool isInitializedAlready;
public void InitializePurchasing()
{
// If we have already connected to Purchasing ...
if (IsInitialized())
{
// ... we are done here.
return;
}
SetupBuilder();
// Create a builder, first passing in a suite of Unity provided stores.
Init();
}
[EasyButtons.Button]
public void CheckInitialized()
{
isInitializedAlready = IsInitialized();
}
ConfigurationBuilder builder;
[EasyButtons.Button]
public void SetupBuilder()
{
builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
builder.AddProduct(tokens1, ProductType.Consumable);
builder.AddProduct(tokens5, ProductType.Consumable);
builder.AddProduct(tokens10, ProductType.Consumable);
builder.AddProduct(caps1000, ProductType.Consumable);
builder.AddProduct(caps2000, ProductType.Consumable);
builder.AddProduct(caps4000, ProductType.Consumable);
builder.AddProduct(crate, ProductType.Consumable);
builder.AddProduct(ultimate_wanderer, ProductType.Consumable);
builder.AddProduct(starterpack, ProductType.Consumable);
builder.AddProduct(weaponpack, ProductType.Consumable);
builder.AddProduct(van, ProductType.Consumable);
builder.AddProduct(scavengerMaterial, ProductType.NonConsumable);
builder.AddProduct(remove_banner, ProductType.NonConsumable);
builder.AddProduct(max_bag, ProductType.NonConsumable);
builder.AddProduct(infinitevan, ProductType.NonConsumable);
builder.AddProduct(subscription, ProductType.Subscription);
//builder.AddProduct(subscription, ProductType.Subscription);
// Kick off the remainder of the set-up with an asynchrounous call, passing the configuration
// and this class' instance. Expect a response either in OnInitialized or OnInitializeFailed.
}
public void Init()
{
UnityPurchasing.Initialize(this, builder);
}
private bool IsInitialized()
{
// Only say we are initialized if both the Purchasing references are set.
return m_StoreController != null && m_StoreExtensionProvider != null;
}
public void BuyConsumable()
{
// Buy the consumable product using its general identifier. Expect a response either
// through ProcessPurchase or OnPurchaseFailed asynchronously.
BuyProductID(kProductIDConsumable);
}
public void BuyNonConsumable()
{
// Buy the non-consumable product using its general identifier. Expect a response either
// through ProcessPurchase or OnPurchaseFailed asynchronously.
BuyProductID(kProductIDNonConsumable);
}
public void BuySubscription()
{
// Buy the subscription product using its the general identifier. Expect a response either
// through ProcessPurchase or OnPurchaseFailed asynchronously.
// Notice how we use the general product identifier in spite of this ID being mapped to
// custom store-specific identifiers above.
BuyProductID(subscription);
}
void BuyProductID(string productId)
{
if (!Application.isMobilePlatform && !Application.isEditor)
{
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/OnlyOnMobile"), 6);
return;
}
// If Purchasing has been initialized ...
if (IsInitialized())
{
// ... look up the Product reference with the general product identifier and the Purchasing
// system's products collection.
Product product = m_StoreController.products.WithID(productId);
// If the look up found a product for this device's store and that product is ready to be sold ...
if (product != null && product.availableToPurchase)
{
Debug.Log(string.Format("Purchasing product asychronously: '{0}'", product.definition.id));
// ... buy the product. Expect a response either through ProcessPurchase or OnPurchaseFailed
// asynchronously.
m_StoreController.InitiatePurchase(product);
}
// Otherwise ...
else
{
// ... report the product look-up failure situation
Debug.Log("BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase");
}
}
// Otherwise ...
else
{
// ... report the fact Purchasing has not succeeded initializing yet. Consider waiting longer or
// retrying initiailization.
Debug.Log("BuyProductID FAIL. Not initialized.");
}
}
// Restore purchases previously made by this customer. Some platforms automatically restore purchases, like Google.
// Apple currently requires explicit purchase restoration for IAP, conditionally displaying a password prompt.
[EasyButtons.Button]
public void RestorePurchases()
{
// If Purchasing has not yet been set up ...
if (!IsInitialized())
{
// ... report the situation and stop restoring. Consider either waiting longer, or retrying initialization.
Debug.Log("RestorePurchases FAIL. Not initialized.");
return;
}
// If we are running on an Apple device ...
if (Application.platform == RuntimePlatform.IPhonePlayer ||
Application.platform == RuntimePlatform.OSXPlayer)
{
// ... begin restoring purchases
Debug.Log("RestorePurchases started ...");
// Fetch the Apple store-specific subsystem.
var apple = m_StoreExtensionProvider.GetExtension<IAppleExtensions>();
// Begin the asynchronous process of restoring purchases. Expect a confirmation response in
// the Action<bool> below, and ProcessPurchase if there are previously purchased products to restore.
apple.RestoreTransactions((result) =>
{
CheckProduct(scavengerMaterial);
CheckProduct(remove_banner);
CheckProduct(max_bag);
CheckProduct(subscription);
CheckProduct(infinitevan);
// The first phase of restoration. If no more responses are received on ProcessPurchase then
// no purchases are available to be restored.
Debug.Log("RestorePurchases continuing: " + result + ". If no further messages, no purchases available to restore.");
});
}
// Otherwise ...
else
{
// We are not running on an Apple device. No work is necessary to restore purchases.
Debug.Log("RestorePurchases FAIL. Not supported on this platform. Current = " + Application.platform);
}
}
//
// --- 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;
CheckProduct(scavengerMaterial);
CheckProduct(remove_banner);
CheckProduct(max_bag);
CheckProduct(subscription);
CheckProduct(infinitevan);
}
bool BannerSaved()
{
foreach (SaveEntry saveEntry in IG_CloudSaving.instance.LocalData.PersistentSaves)
{
if (saveEntry.key == "BannerRemoved" && saveEntry.value == "true")
{
return true;
}
}
return false;
}
void CheckProduct(string id)
{
Product product = m_StoreController.products.WithID(id);
if (product != null)
{
var name = product.metadata.localizedTitle;
//CustomDebug._LogError($"Product = {id} = has receipt = {product.hasReceipt} -------- name given for product = {name} ----- product name = {product} ----- product ID = {product.transactionID}");
if ((id == remove_banner && product.hasReceipt) || BannerSaved())
{
SavedFile.SetBool("BannerRemoved", true, true);
BannerAdvert.instance.HideBanner();
BannerAdvert.BannerRemoved = true;
}
if (id == scavengerMaterial && product.hasReceipt)
{
SavedFile.SetBool("ScavengerMaterial", true, true);
}
if (id == max_bag && product.hasReceipt)
{
SavedFile.SetBool("MaxBag", true, true);
UpgradeManager.BagMaxed = true;
}
if (id == subscription)
{
if (Subscription.instance) Subscription.instance.Subscribe(product.hasReceipt);
else { CustomDebug._LogError("Subscription manager not initiliazed"); }
if (product.hasReceipt)
BannerAdvert.instance.HideBanner();
}
if (id == infinitevan && product.hasReceipt)
{
CamperVan.VanWarranty = true;
SavedFile.SetBool("InfiniteVan", true, true);
}
}
}
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)
{
if (String.Equals(args.purchasedProduct.definition.id, tokens1, StringComparison.Ordinal))
{
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/You have purchased") + " 1 token!", 3);
GameManager.GM.Token += 1;
GameManager.GM.logText = "You have purchased 1 token!";
GameManager.GM.SaveDialogueMessage();
GameManager.GM.SavePrefs();
SoundHandler.s.Transaction.Play();
SendAnalytics(tokens1);
}
else if (String.Equals(args.purchasedProduct.definition.id, tokens5, StringComparison.Ordinal))
{
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/You have purchased") + " 5 tokens!", 3);
GameManager.GM.Token += 5;
GameManager.GM.logText = "You have purchased 5 tokens!";
GameManager.GM.SaveDialogueMessage();
GameManager.GM.SavePrefs();
SoundHandler.s.Transaction.Play();
SendAnalytics(tokens5);
}
else if (String.Equals(args.purchasedProduct.definition.id, caps1000, StringComparison.Ordinal))
{
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/You have purchased") + " 1000 caps!", 3);
CapsManager.instance.UpdateCaps(1000);
WandererProgress.TotalCaps += 1000;
WandererProgress.WP.SavePrefs();
GameManager.GM.logText = "You have purchased 1000 caps!";
GameManager.GM.SaveDialogueMessage();
GameManager.GM.SavePrefs();
SoundHandler.s.Transaction.Play();
SendAnalytics(caps1000);
}
else if (String.Equals(args.purchasedProduct.definition.id, caps2000, StringComparison.Ordinal))
{
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/You have purchased") + " 5000 caps!", 3);
CapsManager.instance.UpdateCaps(5000);
WandererProgress.TotalCaps += 5000;
WandererProgress.WP.SavePrefs();
GameManager.GM.logText = "You have purchased 5000 caps!";
GameManager.GM.SaveDialogueMessage();
GameManager.GM.SavePrefs();
SoundHandler.s.Transaction.Play();
SendAnalytics(caps2000);
}
else if (String.Equals(args.purchasedProduct.definition.id, caps4000, StringComparison.Ordinal))
{
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/You have purchased") + " 10000 caps!", 3);
CapsManager.instance.UpdateCaps(10000);
WandererProgress.TotalCaps += 10000;
WandererProgress.WP.SavePrefs();
GameManager.GM.logText = "You have purchased 10000 caps!";
GameManager.GM.SaveDialogueMessage();
GameManager.GM.SavePrefs();
SoundHandler.s.Transaction.Play();
SendAnalytics(caps4000);
}
else if (String.Equals(args.purchasedProduct.definition.id, tokens10, StringComparison.Ordinal))
{
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/You have purchased") + " 10 tokens!", 3);
GameManager.GM.Token += 10;
GameManager.GM.logText = "You have purchased 10 tokens!";
GameManager.GM.SaveDialogueMessage();
GameManager.GM.SavePrefs();
SoundHandler.s.Transaction.Play();
SendAnalytics(tokens10);
}
else if (String.Equals(args.purchasedProduct.definition.id, crate, StringComparison.Ordinal))
{
if (ShopSpecials.instance) ShopSpecials.instance.GiveToPlayer();
else ShowShopSpecialsPopup.instance.GiveToPlayer();
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/You have purchased") + " 1 WANDERER CRATE!", 3);
GameManager.GM.logText = "You have purchased a WANDERER CRATE!";
GameManager.GM.SaveDialogueMessage();
GameManager.GM.SavePrefs();
SoundHandler.s.Transaction.Play();
SendAnalytics(crate);
}
else if (String.Equals(args.purchasedProduct.definition.id, ultimate_wanderer, StringComparison.Ordinal))
{
if (ShopSpecials.instance) ShopSpecials.instance.GiveToPlayer();
else ShowShopSpecialsPopup.instance.GiveToPlayer();
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/You have purchased") + " 1 ULTIMATE WANDERER CRATE!", 3);
GameManager.GM.logText = "You have purchased the ULTIMATE WANDERER CRATE!";
GameManager.GM.SaveDialogueMessage();
GameManager.GM.SavePrefs();
SoundHandler.s.Transaction.Play();
SendAnalytics(ultimate_wanderer);
}
else if (String.Equals(args.purchasedProduct.definition.id, starterpack, StringComparison.Ordinal))
{
if (ShopSpecials.instance) ShopSpecials.instance.GiveToPlayer();
else ShowShopSpecialsPopup.instance.GiveToPlayer();
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/You have purchased") + " 1 STARTER PACK!", 3);
GameManager.GM.logText = "You have purchased a STARTER PACK!";
GameManager.GM.SaveDialogueMessage();
GameManager.GM.SavePrefs();
SoundHandler.s.Transaction.Play();
SendAnalytics(starterpack);
}
else if (String.Equals(args.purchasedProduct.definition.id, weaponpack, StringComparison.Ordinal))
{
if (ShopSpecials.instance) ShopSpecials.instance.GiveToPlayer();
else ShowShopSpecialsPopup.instance.GiveToPlayer();
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/You have purchased") + " 1 WEAPON CRATE!", 3);
GameManager.GM.logText = "You have purchased a WEAPON CRATE!";
GameManager.GM.SaveDialogueMessage();
GameManager.GM.SavePrefs();
SoundHandler.s.Transaction.Play();
SendAnalytics(weaponpack);
}
else if (String.Equals(args.purchasedProduct.definition.id, van, StringComparison.Ordinal))
{
if (ShopSpecials.instance) ShopSpecials.instance.GiveToPlayer();
else ShowShopSpecialsPopup.instance.GiveToPlayer();
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/You have purchased") + " 1 VAN PACKAGE!", 3);
GameManager.GM.logText = "You have purchased the VAN PACKAGE!";
GameManager.GM.SaveDialogueMessage();
GameManager.GM.SavePrefs();
SoundHandler.s.Transaction.Play();
SendAnalytics(van);
}
else if (String.Equals(args.purchasedProduct.definition.id, scavengerMaterial, StringComparison.Ordinal))
{
SavedFile.SetBool("ScavengerMaterial", true, true);
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/You have purchased the") + " material scavenger!", 3);
GameManager.GM.logText = "You have purchased the material scavenger!";
GameManager.GM.SaveDialogueMessage();
GameManager.GM.SavePrefs();
SoundHandler.s.Transaction.Play();
SendAnalytics(scavengerMaterial);
}
else if (String.Equals(args.purchasedProduct.definition.id, remove_banner, StringComparison.Ordinal))
{
SavedFile.SetBool("BannerRemoved", true, true);
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/You have removed the advert banner!... THANKS for your support!"), 3);
GameManager.GM.logText = "You have removed the advert banner!... THANKS for your support!";
GameManager.GM.SaveDialogueMessage();
BannerAdvert.instance.HideBanner();
SoundHandler.s.Transaction.Play();
BannerAdvert.BannerRemoved = true;
SendAnalytics(remove_banner);
}
else if (String.Equals(args.purchasedProduct.definition.id, max_bag, StringComparison.Ordinal))
{
SavedFile.SetBool("MaxBag", true, true);
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/Bag level maxed out!"), 3);
GameManager.GM.logText = "Bag level maxed out!";
GameManager.GM.SaveDialogueMessage();
SoundHandler.s.Transaction.Play();
UpgradeManager.BagMaxed = true;
SendAnalytics(max_bag);
}
else if (String.Equals(args.purchasedProduct.definition.id, subscription, StringComparison.Ordinal))
{
Subscription.instance.Subscribe(true);
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/Subscription enabled!"), 3);
GameManager.GM.logText = "Subscription enabled!";
SoundHandler.s.Transaction.Play();
SendAnalytics(subscription);
}
else if (String.Equals(args.purchasedProduct.definition.id, infinitevan, StringComparison.Ordinal))
{
SavedFile.SetBool("InfiniteVan", true, true);
CamperVan.VanWarranty = true;
ScreenWarning.instance.ShowWarning(LocalizationManager.GetTranslation("Popup/Camper Van Warranty Purchased!"), 3);
GameManager.GM.logText = "Camper Van Warranty Purchased!";
SoundHandler.s.Transaction.Play();
SendAnalytics(infinitevan);
}
// 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 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));
}
void SendAnalytics(string id)
{
var product = m_StoreController.products.WithID(id);
string receipt = product.receipt;
string currency = product.metadata.isoCurrencyCode;
int amount = decimal.ToInt32(product.metadata.localizedPrice * 100);
#if UNITY_ANDROID
Receipt receiptAndroid = JsonUtility.FromJson<Receipt>(receipt);
PayloadAndroid receiptPayload = JsonUtility.FromJson<PayloadAndroid>(receiptAndroid.Payload);
GameAnalytics.NewDesignEvent("Play Time before purchase: " + Utils.FormatSeconds(PlayTimer.instance.TotalPlayTime));
GameAnalytics.NewBusinessEventGooglePlay(currency, amount, id.ToString(), kProductIDConsumable, "my_cart_type", receiptPayload.json, receiptPayload.signature);
#endif
#if UNITY_IPHONE
Receipt receiptiOS = JsonUtility.FromJson<Receipt> (receipt);
string receiptPayload = receiptiOS.Payload;
GameAnalytics.NewBusinessEventIOS (currency, amount, id.ToString(), kProductIDConsumable, "my_cart_type", receiptPayload);
#endif
}
// Update is called once per frame
public void Token1()
{
BuyProductID(tokens1);
}
public void Token5()
{
BuyProductID(tokens5);
}
public void Token10()
{
BuyProductID(tokens10);
}
public void Cap1000()
{
BuyProductID(caps1000);
}
public void Cap2000()
{
BuyProductID(caps2000);
}
public void Cap4000()
{
BuyProductID(caps4000);
}
public void Crate()
{
BuyProductID(crate);
}
public void Ultimate_Wanderer()
{
BuyProductID(ultimate_wanderer);
}
public void Van_Warranty()
{
BuyProductID(infinitevan);
}
public void StarterPack()
{
BuyProductID(starterpack);
}
public void WeaponPack()
{
BuyProductID(weaponpack);
}
public void UnlockVan()
{
BuyProductID(van);
}
[EasyButtons.Button]
public void UnlockScavengerMaterial()
{
BuyProductID(scavengerMaterial);
}
[EasyButtons.Button]
public void RemoveBanner()
{
BuyProductID(remove_banner);
}
[EasyButtons.Button]
public void MaxBag()
{
BuyProductID(max_bag);
}
[EasyButtons.Button]
public void CheckIfSubscriptionIsActive()
{
var apple = m_StoreExtensionProvider.GetExtension<IAppleExtensions>();
Dictionary<string, string> introductory_info_dict = apple.GetIntroductoryPriceDictionary();
foreach (var item in m_StoreController.products.all)
{
if (item.availableToPurchase)
{
//#if SUBSCRIPTION_MANAGER
// this is the usage of SubscriptionManager class
if (item.receipt != null)
{
if (item.definition.type == ProductType.Subscription)
{
if (checkIfProductIsAvailableForSubscriptionManager(item.receipt))
{
string intro_json = (introductory_info_dict == null || !introductory_info_dict.ContainsKey(item.definition.storeSpecificId)) ? null : introductory_info_dict[item.definition.storeSpecificId];
SubscriptionManager p = new SubscriptionManager(item, intro_json);
SubscriptionInfo info = p.getSubscriptionInfo();
Debug.Log("product id is: " + info.getProductId());
Debug.Log("purchase date is: " + info.getPurchaseDate());
Debug.Log("subscription next billing date is: " + info.getExpireDate());
Debug.Log("is subscribed? " + info.isSubscribed().ToString());
Debug.Log("is expired? " + info.isExpired().ToString());
Debug.Log("is cancelled? " + info.isCancelled());
Debug.Log("product is in free trial peroid? " + info.isFreeTrial());
Debug.Log("product is auto renewing? " + info.isAutoRenewing());
Debug.Log("subscription remaining valid time until next billing date is: " + info.getRemainingTime());
Debug.Log("is this product in introductory price period? " + info.isIntroductoryPricePeriod());
Debug.Log("the product introductory localized price is: " + info.getIntroductoryPrice());
Debug.Log("the product introductory price period is: " + info.getIntroductoryPricePeriod());
Debug.Log("the number of product introductory price period cycles is: " + info.getIntroductoryPricePeriodCycles());
}
else
{
Debug.Log("This product is not available for SubscriptionManager class, only products that are purchase by 1.19+ SDK can use this class.");
}
}
else
{
Debug.Log($"{item.definition} is not a subscription product");
}
}
else
{
Debug.Log($"{item.definition} should have a valid receipt");
}
//#endif
}
}
}
private bool checkIfProductIsAvailableForSubscriptionManager(string receipt)
{
var receipt_wrapper = (Dictionary<string, object>)MiniJson.JsonDecode(receipt);
if (!receipt_wrapper.ContainsKey("Store") || !receipt_wrapper.ContainsKey("Payload"))
{
Debug.Log("The product receipt does not contain enough information");
return false;
}
var store = (string)receipt_wrapper["Store"];
var payload = (string)receipt_wrapper["Payload"];
if (payload != null)
{
switch (store)
{
case GooglePlay.Name:
{
var payload_wrapper = (Dictionary<string, object>)MiniJson.JsonDecode(payload);
if (!payload_wrapper.ContainsKey("json"))
{
Debug.Log("The product receipt does not contain enough information, the 'json' field is missing");
return false;
}
var original_json_payload_wrapper = (Dictionary<string, object>)MiniJson.JsonDecode((string)payload_wrapper["json"]);
if (original_json_payload_wrapper == null || !original_json_payload_wrapper.ContainsKey("developerPayload"))
{
Debug.Log("The product receipt does not contain enough information, the 'developerPayload' field is missing");
return false;
}
var developerPayloadJSON = (string)original_json_payload_wrapper["developerPayload"];
var developerPayload_wrapper = (Dictionary<string, object>)MiniJson.JsonDecode(developerPayloadJSON);
if (developerPayload_wrapper == null || !developerPayload_wrapper.ContainsKey("is_free_trial") || !developerPayload_wrapper.ContainsKey("has_introductory_price_trial"))
{
Debug.Log("The product receipt does not contain enough information, the product is not purchased using 1.19 or later");
return false;
}
return true;
}
case AppleAppStore.Name:
case AmazonApps.Name:
case MacAppStore.Name:
{
return true;
}
default:
{
return false;
}
}
}
return false;
}
}