//when the window gets opened void OnEnable() { //reconnect reference if (iapEditor == null) { iapEditor = this; } //get reference to the shop and cache it shop = GameObject.FindObjectOfType(typeof(ShopManager)) as ShopManager; script = FindIAPManager(); //could not get prefab, non-existent? if (script == null) { return; } if (shop) { RemoveContainerConnections(); } //set current currency index from -1 to first one, //if currencies were specified if (script.currency.Count > 0) { currencyIndex = 0; } }
//when the buy button has been clicked, here we try to purchase this item //maps to the corresponding purchase methods of IAPManager public void Purchase() { //differ between IAP type switch (type) { case IAPType.consumable: IAPManager.PurchaseConsumableProduct(this.productId); break; case IAPType.nonConsumable: IAPManager.PurchaseNonconsumableProduct(this.productId); break; case IAPType.subscription: IAPManager.PurchaseSubscription(this.productId); break; case IAPType.consumableVirtual: IAPManager.PurchaseConsumableVirtualProduct(this.productId); break; case IAPType.nonConsumableVirtual: IAPManager.PurchaseNonconsumableVirtualProduct(this.productId); break; } //hide buy button once a purchase was made //only when an additional buy trigger was set if (buyTrigger) { ConfirmPurchase(false); } }
/// <summary> /// Initialize the instance using the specified IStoreCallback. /// </summary> public virtual void Initialize(IStoreCallback callback) { this.callback = callback; AndroidInAppPurchaseManager.ActionBillingSetupFinished += OnInitialized; AndroidInAppPurchaseManager.ActionRetrieveProducsFinished += OnProductsRetrieved; AndroidInAppPurchaseManager.ActionProductPurchased += OnPurchaseSucceeded; AndroidInAppPurchaseManager.ActionProductConsumed += OnTransactionFinished; if (!AndroidNativeSettings.Instance.IsBase64KeyWasReplaced) { Debug.LogWarning("Google Store Public Key missing in Android Native Settings. " + "Purchases for real money won't be supported on the device."); } definitions = IAPManager.GetProductDefinitions(); AndroidNativeSettings.Instance.InAppProducts.Clear(); for (int i = 0; i < definitions.Length; i++) { AndroidInAppPurchaseManager.Client.AddProduct(definitions[i].storeSpecificId); #if UNITY_EDITOR IAPObject obj = IAPManager.GetIAPObject(definitions[i].id); AndroidNativeSettings.Instance.InAppProducts[i].Title = obj.title; AndroidNativeSettings.Instance.InAppProducts[i].Description = obj.description; AndroidNativeSettings.Instance.InAppProducts[i].LocalizedPrice = obj.realPrice; #endif } AndroidInAppPurchaseManager.Client.Connect(); }
public string GetIdentifier() { string local = null; switch (Application.platform) { case RuntimePlatform.Android: if (IAPManager.GetInstance().androidPlatform == IAPPlatform.GooglePlay) { local = localId[(int)IAPPlatform.GooglePlay].GetIdentifier(); } else if (IAPManager.GetInstance().androidPlatform == IAPPlatform.Amazon) { local = localId[(int)IAPPlatform.Amazon].GetIdentifier(); } break; case RuntimePlatform.IPhonePlayer: local = localId[(int)IAPPlatform.iOSAppStore].GetIdentifier(); break; case RuntimePlatform.WP8Player: local = localId[(int)IAPPlatform.WindowsPhone8].GetIdentifier(); break; } if (!string.IsNullOrEmpty(local)) { return(local); } else { return(id); } }
/// <summary> /// Purchase overload for virtual products, as they differ in their workflow on PlayFab. /// Also the virtual currency funds are checked locally before forwarding the request to PlayFab. /// </summary> public void Purchase(IAPObject obj) { int curIndex = 0; for (int i = 0; i < obj.virtualPrice.Count; i++) { if (obj.virtualPrice[i].amount != 0) { curIndex = i; break; } } //local check before doing the request if (DBManager.GetFunds(obj.virtualPrice[curIndex].name) < obj.virtualPrice[curIndex].amount) { IAPManager.OnPurchaseFailed("Insufficient Funds."); return; } PurchaseItemRequest request = new PurchaseItemRequest() { ItemId = obj.id, VirtualCurrency = obj.virtualPrice[curIndex].name.Substring(0, 2).ToUpper(), Price = obj.virtualPrice[curIndex].amount }; PlayFabClientAPI.PurchaseItem(request, OnPurchaseSucceeded, OnVirtualPurchaseFailed); }
//getting the items declared in PlayFab's catalog and converting them to Unity IAP format private void OnCatalogRetrieved(GetCatalogItemsResult result) { for (int i = 0; i < result.Catalog.Count; i++) { CatalogItem catalogItem = result.Catalog[i]; string itemId = IAPManager.GetIAPIdentifier(catalogItem.ItemId); if (!IAPManager.GetIAPKeys().Contains(itemId) || products.ContainsKey(itemId)) { continue; } ApplyCatalogItem(itemId, catalogItem); decimal price = 0; string priceString = ""; string currency = catalogItem.VirtualCurrencyPrices.Keys.First(); if (currency == "RM") { price = (decimal)catalogItem.VirtualCurrencyPrices[currency] / 100m; priceString = price.ToString("C"); } else { price = catalogItem.VirtualCurrencyPrices[currency]; priceString = price.ToString(); } products.Add(itemId, new ProductDescription(itemId, new ProductMetadata(priceString, catalogItem.DisplayName, catalogItem.Description, "USD", price))); } if (callback != null) { callback.OnProductsRetrieved(products.Values.ToList()); } }
private void OnProductsRetrieved(Result result) { this.products = new Dictionary <string, ProductDescription>(); if (!result.IsSucceeded) { OnSetupFailed(result.Error.Code + ", " + result.Error.Message); return; } List <IOSProductTemplate> list = IOSInAppPurchaseManager.Instance.Products; string globalId = null; string storeId = null; for (int i = 0; i < list.Count; i++) { storeId = list[i].Id; globalId = IAPManager.GetIAPIdentifier(storeId); if (!products.ContainsKey(globalId)) { products.Add(globalId, new ProductDescription(storeId, new ProductMetadata(list[i].LocalizedPrice, list[i].DisplayName, list[i].Description, list[i].CurrencyCode, (decimal)list[i].Price))); } if (PlayerPrefs.HasKey(globalId)) { products[globalId] = new ProductDescription(storeId, products[globalId].metadata, DBManager.GetReceipt(globalId), ""); } } callback.OnProductsRetrieved(products.Values.ToList()); }
//if there is no IAP Manager in the scene, the ShopManager //will try to instantiate the prefab itself IEnumerator Start() { if (!IAPManager.GetInstance()) { Debug.LogWarning("ShopManager: Could not find IAPManager prefab. Have you placed it in the first scene " + "of your app and started from there? Instantiating copy..."); GameObject obj = Instantiate(Resources.Load("IAPManager", typeof(GameObject))) as GameObject; //remove clone tag from its name. not necessary, but nice to have obj.name = obj.name.Replace("(Clone)", ""); //trigger self-initialization manually yield return(new WaitForEndOfFrame()); IAPManager.GetInstance().OnSceneWasLoaded(SceneManager.GetActiveScene(), LoadSceneMode.Single); //the containers have tried to initialize but disabled themselves already, //trigger initialization of UI grid reordering again yield return(new WaitForEndOfFrame()); for (int i = 0; i < containers.Count; i++) { if (containers[i].parent != null && containers[i].parent.isActiveAndEnabled) { containers[i].parent.StartCoroutine(containers[i].parent.Start()); } } } }
/// <summary> /// Initialize the instance using the specified IStoreCallback. /// </summary> public void Initialize(IStoreCallback callback) { this.callback = callback; IOSInAppPurchaseManager.OnStoreKitInitComplete += OnProductsRetrieved; IOSInAppPurchaseManager.OnTransactionComplete += OnPurchaseSucceeded; #if !UNITY_EDITOR if (!IOSInAppPurchaseManager.Instance.IsInAppPurchasesEnabled) { OnSetupFailed("Apple App Store billing is disabled."); return; } #endif definitions = IAPManager.GetProductDefinitions(); IOSNativeSettings.Instance.InAppProducts.Clear(); for (int i = 0; i < definitions.Length; i++) { IOSInAppPurchaseManager.Instance.AddProductId(definitions[i].storeSpecificId); #if UNITY_EDITOR IAPObject obj = IAPManager.GetIAPObject(definitions[i].id); IOSNativeSettings.Instance.InAppProducts[i].DisplayName = obj.title; IOSNativeSettings.Instance.InAppProducts[i].Description = obj.description; IOSNativeSettings.Instance.InAppProducts[i].LocalizedPrice = obj.realPrice; #endif } IOSInAppPurchaseManager.Instance.LoadStore(); }
/// <summary> /// returns list that holds all purchased product ids /// for upgradeable products this only returns the current one /// </summary> public static List <string> GetAllPurchased() { //get location string, //create temporary string list string loc = instance.content; List <string> temp = new List <string>(); //find the correct content JSON node JSONNode node = instance.gameData[loc]; //loop through keys and add product ids //that were purchased (true) foreach (string id in node.AsObject.Keys) { //check for purchase if (node[id].AsBool == false) { continue; } //checking base product or upgrade but it is not the current one if (id != IAPManager.GetCurrentUpgrade(id)) { continue; } temp.Add(id); } //convert and return array return(temp); }
/// <summary> /// Returns list that holds all purchased product ids. By default, /// for upgradeable products this only returns the current active one. /// </summary> public static List <string> GetAllPurchased(bool withUpgrades = false) { //create temporary string list List <string> temp = new List <string>(); //find the correct content JSON node JSONNode node = instance.gameData[contentKey]; //merge paid and free products (which are not saved on disk) List <string> mergedIDs = new List <string>(node.AsObject.Keys); mergedIDs = mergedIDs.Union(IAPManager.GetIAPKeys()).ToList(); //loop through keys and add product ids for (int i = 0; i < mergedIDs.Count; i++) { //check for purchase if (GetPurchase(mergedIDs[i]) == 0) { continue; } //checking base product or upgrade but it is not the current one if (!withUpgrades && mergedIDs[i] != IAPManager.GetCurrentUpgrade(mergedIDs[i])) { continue; } temp.Add(mergedIDs[i]); } //convert and return array return(temp); }
/// <summary> /// Set this item to 'purchased' state (true), or unpurchased state (false) for fake purchases. /// </summary> public void Purchased(bool state) { //in case we restored an old purchase on a //locked item, we have to unlock it first Unlock(); //back to unpurchased state, deselect if (!state) { Deselect(); } //activate the select button else if (selectButton) { selectButton.SetActive(state); } //initialize variables for a product with upgrades IAPObject obj = IAPManager.GetIAPObject(productId); bool hasUpgrade = false; string nextUpgrade = obj.req.nextId; //in case this good has upgrades, here we find the next upgrade //and replace displayed item data in the store with its upgrade details if (!string.IsNullOrEmpty(nextUpgrade)) { hasUpgrade = true; Init(IAPManager.GetIAPObject(nextUpgrade)); } //take upgrade state into account if (state && hasUpgrade) { state = !hasUpgrade; } //activate the sold gameobject if (sold) { sold.SetActive(state); } //hide both buy trigger and buy button, for ignoring further purchase clicks. //but don't do that for subscriptions, so that the user could easily renew it if ((int)obj.type > 1) { return; } if (buyTrigger) { buyTrigger.SetActive(!state); buyButton.SetActive(false); } else { buyButton.SetActive(!state); } }
//initialize IAPs, billing systems and database, //as well as shop components in this order void Awake() { //make sure we keep one instance of this script in the game if (instance) { Destroy(gameObject); return; } DontDestroyOnLoad(this); isDebug = Debug.isDebugBuild; //set static reference instance = this; DBManager dbManager = GetComponent <DBManager>(); validator = GetComponent <ReceiptValidator>(); #if PLAYFAB playfabManager = null; GameObject playfabGO = GameObject.Find("PlayfabManager"); if (!playfabGO) { Debug.LogWarning("IAPManager: Playfab is enabled, but could not find PlayfabManager prefab. Have you placed it in the first scene " + "of your app and started from there? Instantiating temporary copy..."); playfabGO = Instantiate(Resources.Load("PlayfabManager", typeof(GameObject))) as GameObject; //remove clone tag from its name. not necessary, but nice to have playfabGO.name = playfabGO.name.Replace("(Clone)", ""); } playfabManager = playfabGO.GetComponent <PlayfabManager>(); if (validator == null) { validator = gameObject.AddComponent <ReceiptValidatorService>(); } #if !PLAYFAB_VALIDATION dbManager.memoryOnly = true; if (isDebug) { Debug.Log("PlayFab (online mode) is enabled: IAP data will not be saved on devices."); } #endif #endif //populate IAP dictionary and arrays with product ids SceneManager.sceneLoaded += OnSceneWasLoaded; dbManager.Init(); InitIds(); //do not self-initialize when using PlayFab services (full): //wait for its login callback for querying store later #if PLAYFAB && !PLAYFAB_VALIDATION return; #endif Initialize(); }
private void OnRestoreSucceeded(Result result) { if (result == null || !result.IsSucceeded) { IAPManager.OnTransactionsRestored(false); return; } IAPManager.OnTransactionsRestored(true); }
/// <summary> /// This will be called when a purchase completes. /// Optional: verify new product receipt. /// </summary> public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e) { if (IAPManager.GetIAPObject(e.purchasedProduct.definition.id) == null) { return(PurchaseProcessingResult.Complete); } /* * //IN DEVELOPMENT until CloudMoolah comes out of beta * //CloudMoolah payment request * if(Application.platform == RuntimePlatform.Android && StandardPurchasingModule.Instance().androidStore == AndroidStore.CloudMoolah) * { * extensions.GetExtension<IMoolahExtension>().RequestPayOut(e.purchasedProduct.transactionID, (string transactionID, RequestPayOutState state, string message) => * { * Debug.Log("RequestPayOut callback: " + transactionID + ", " + state + ", " + message); * * if (state == RequestPayOutState.RequestPayOutSucceed) * { * controller.ConfirmPendingPurchase(e.purchasedProduct); * PurchaseVerified(e.purchasedProduct.definition.id); * } * }); * * return PurchaseProcessingResult.Pending; * } */ #if UNITY_IOS || UNITY_TVOS if (validator && validator.shouldValidate(VerificationType.onStart)) { DBManager.SaveReceipt("Receipt", e.purchasedProduct.receipt); } #endif //when auto-restoring transactions on first app launch, the time between OnInitialized and //this method will be very short. So check that and do not validate for restored products //also do not validate when using PlayFab and restoring transactions on Apple as there is //currently a Unity IAP bug that causes PlayFab to decline any restore transactions if ((Time.unscaledTime - initializeTime) > 0.1f && !isRestoringTransactions && validator && validator.shouldValidate(VerificationType.onPurchase)) { validator.Validate(e.purchasedProduct); if (!(validator is ReceiptValidatorClient)) { return(PurchaseProcessingResult.Pending); } } else { PurchaseVerified(e.purchasedProduct.definition.id); } // Indicate we have handled this purchase, we will not be informed of it again return(PurchaseProcessingResult.Complete); }
//method for remote catalog config //converts a (downloaded) config string for virtual products into JSON nodes and overwrites //existing IAP objects with new properties, after doing a null reference check for empty nodes. private void ApplyCatalogItem(string id, CatalogItem item) { IAPObject obj = IAPManager.GetIAPObject(id); if (!obj.fetch) { return; } switch (obj.editorType) { case IAPType.Currency: foreach (string curKey in item.Bundle.BundledVirtualCurrencies.Keys) { IAPCurrency cur = obj.virtualPrice.Find(x => x.name.StartsWith(curKey, System.StringComparison.OrdinalIgnoreCase)); if (cur != null) { cur.amount = (int)item.Bundle.BundledVirtualCurrencies[curKey]; } } break; case IAPType.Virtual: foreach (string curKey in item.VirtualCurrencyPrices.Keys) { IAPCurrency cur = obj.virtualPrice.Find(x => x.name.StartsWith(curKey, System.StringComparison.OrdinalIgnoreCase)); if (cur != null) { cur.amount = (int)item.VirtualCurrencyPrices[curKey]; } } break; } if (!string.IsNullOrEmpty(item.CustomData)) { JSONNode data = JSON.Parse(item.CustomData); if (!string.IsNullOrEmpty(data["requirement"].ToString())) { data = data["requirement"]; if (!string.IsNullOrEmpty(data["entry"])) { obj.req.entry = data["entry"]; } if (!string.IsNullOrEmpty(data["labelText"])) { obj.req.labelText = data["labelText"]; } if (!string.IsNullOrEmpty(data["target"])) { obj.req.target = data["target"].AsInt; } } } }
//if there is no IAP Manager in the scene, //the Shop Manager will try to instantiate the prefab void Start() { if (!IAPManager.GetInstance()) { Debug.LogWarning("ShopManager: Could not find IAPManager prefab. Have you placed it in the first scene " + "of your app and started from there? Instantiating temporary copy..."); GameObject obj = Instantiate(Resources.Load("IAPManager", typeof(GameObject))) as GameObject; //remove clone tag from its name. not necessary, but nice to have obj.name = obj.name.Replace("(Clone)", ""); } }
/// <summary> /// When the buy button has been clicked, here we try to purchase this item. /// This calls into the corresponding billing workflow of the IAPManager. /// </summary> public void Purchase() { IAPManager.PurchaseProduct(this.productId); //hide buy button once a purchase was made //only when an additional buy trigger was set if (buyTrigger) { ConfirmPurchase(false); } }
/// <summary> /// Grant non-consumables on the user's inventory on PlayFab. Consumables will be granted only /// locally to minimize requests - please call SetFunds or SetPlayerData afterwards if needed. /// </summary> public static IEnumerator SetPurchase(List <string> productIDs) { //create a separate list for non-consumables to request List <string> cloudProducts = new List <string>(); for (int i = 0; i < productIDs.Count; i++) { if ((int)IAPManager.GetIAPObject(productIDs[i]).type > 0) { cloudProducts.Add(productIDs[i]); } } bool commit = true; if (cloudProducts.Count > 0) { ExecuteCloudScriptRequest cloudRequest = new ExecuteCloudScriptRequest() { FunctionName = "grantItems", FunctionParameter = new { itemIds = cloudProducts.ToArray() } }; bool result = false; PlayFabClientAPI.ExecuteCloudScript(cloudRequest, (cloudResult) => { result = true; }, (error) => { OnPlayFabError(error); commit = false; result = true; }); while (!result) { yield return(null); } } //only grant products if the cloud request was successful if (commit == true) { for (int i = 0; i < productIDs.Count; i++) { if (DBManager.GetPurchase(productIDs[i]) == 0) { IAPManager.GetInstance().PurchaseVerified(productIDs[i]); } } } yield return(null); }
/// <summary> /// Method for overwriting shop item's properties with online IAP data /// from the App Store servers (those in the developer console). /// When we receive the online item list of products from the IAPManager, /// we loop over our products and check if 'fetch' was checked in the /// IAP Settings editor, then simply reinitialize the items with new data. /// </summary> public static void OverwriteWithFetch(Product[] products) { for (int i = 0; i < products.Length; i++) { string id = products[i].definition.id; IAPObject item = IAPManager.GetIAPObject(id); if (item != null && item.fetch && instance.IAPItems.ContainsKey(id)) { instance.IAPItems[id].Init(products[i]); } } }
/// <summary> /// When the buy button has been clicked, here we try to purchase this item. /// This calls into the corresponding billing workflow of the IAPManager. /// </summary> public void Purchase() { TransformState.instance.PlayButtonClip(); IAPManager.PurchaseProduct(this.productId); //hide buy button once a purchase was made //only when an additional buy trigger was set if (buyTrigger) { ConfirmPurchase(false); } }
/// <summary> /// method for overwriting shop item's properties with online IAP data /// from Google's or Apple's servers (those in the developer console). /// When we receive the online item list of IAPProducts from IAPManager, /// we loop over our products and check if 'fetch' was checked in the /// IAP Settings editor, then simply reinitialize the items with new info /// </summary> public static void OverwriteWithFetch(List <IAPArticle> products) { for (int i = 0; i < products.Count; i++) { string id = IAPManager.GetIAPIdentifier(products[i].id); IAPObject item = IAPManager.GetIAPObject(id); if (item != null && item.fetch && instance.IAPItems.ContainsKey(id)) { instance.IAPItems[id].Init(products[i]); } } }
/// <summary> /// Unlocks items if the requirement for them has been met. You can /// call this method at runtime whenever the player made some /// progress, to ensure your shop items reflect the current state. /// </summary> public static void UnlockItems() { //this method is based on data from the database, //so if we don't have a DBManager instance don't continue if (!DBManager.GetInstance()) { return; } //get list of all shop groups from IAPManager List <IAPGroup> list = IAPManager.GetInstance().IAPs; //loop over groups for (int i = 0; i < list.Count; i++) { //cache current group IAPGroup group = list[i]; //loop over items for (int j = 0; j < group.items.Count; j++) { //cache IAP object IAPObject obj = group.items[j]; if (obj.req == null) { continue; } //cache reference to IAP item instance IAPItem item = GetIAPItem(obj.id); //check if the item reference is empty or set to purchased already if (item == null || DBManager.isPurchased(obj.id)) { continue; } //check if a requirement is set up for this item, //then unlock if the requirement has been met if (!string.IsNullOrEmpty(obj.req.entry) && DBManager.isRequirementMet(obj.req)) { if (IAPManager.isDebug) { Debug.Log("requirement met for: " + obj.id); } item.Unlock(); } } } }
/// <summary> /// Refreshes the visual representation of a specific shop item. /// This is called automatically because of subscribing to the DBManager update event. /// It also means saving performance due to not refreshing all items every time. /// </summary> public void Refresh(string id) { //this method is based on data from the database, //so if we don't have a DBManager instance don't continue if (!DBManager.GetInstance()) { return; } IAPObject obj = IAPManager.GetIAPObject(id); IAPItem item = instance.IAPItems.ContainsKey(id) ? instance.IAPItems[id] : null; if (obj == null || item == null || item.productId != id) { return; } bool isSelected = DBManager.GetSelected(id); bool isPurchased = DBManager.GetPurchase(id) > 0; //double check that selected items are actually owned //if not, correct the entry by setting it to deselected if (isSelected && !isPurchased) { DBManager.SetDeselected(id); isSelected = false; } if (isPurchased) { item.Purchased(true); //in case the item has been selected before, but also auto-select one item per group //more items per group can be pre-selected manually e.g. on app launch if (isSelected || (item.selectButton && !item.deselectButton && DBManager.GetSelectedGroup(IAPManager.GetIAPObjectGroupName(id)).Count == 0)) { item.IsSelected(true); } } else if (!string.IsNullOrEmpty(obj.req.entry) && DBManager.isRequirementMet(obj.req)) { //check if a requirement is set up for this item, //then unlock if the requirement has been met if (IAPManager.isDebug) { Debug.Log("requirement met for: " + obj.id); } item.Unlock(); } }
/// <summary> /// Method for overwriting shop item's properties with localized IAP data from the App Store servers. When we receive /// the online item list of products from the IAPManager, we loop over our products and check if 'fetch' was checked /// in the IAP Settings editor, then simply reinitialize the items by using the new data. /// </summary> public static void OverwriteWithFetch(Product[] products) { for (int i = 0; i < products.Length; i++) { string id = products[i].definition.id; IAPObject item = IAPManager.GetIAPObject(id); if (item == null || !item.fetch || !instance.IAPItems.ContainsKey(id) || item.editorType == IAPType.Virtual) { continue; } instance.IAPItems[id].Init(products[i]); } }
//when the buy button has been clicked, here we try to purchase this item //maps to the corresponding purchase methods of IAPManager //only works on an actual mobile device public void Purchase() { #if UNITY_EDITOR if (type == IAPType.consumable || type == IAPType.nonConsumable || type == IAPType.subscription) { string editorText = "Calling purchase ID: " + this.productId + ".\nYou are not on a mobile device, nothing will happen."; if (ShopManager.GetInstance()) { ShopManager.ShowMessage(editorText); } Debug.Log(editorText); return; } #endif //differ between IAP type switch (type) { case IAPType.consumable: IAPManager.PurchaseConsumableProduct(this.productId); break; case IAPType.nonConsumable: IAPManager.PurchaseNonconsumableProduct(this.productId); break; case IAPType.subscription: IAPManager.PurchaseSubscription(this.productId); break; case IAPType.consumableVirtual: IAPManager.PurchaseConsumableVirtualProduct(this.productId); break; case IAPType.nonConsumableVirtual: IAPManager.PurchaseNonconsumableVirtualProduct(this.productId); break; } //hide buy button once a purchase was made //only when an additional buy trigger was set if (buyTrigger) { ConfirmPurchase(false); } }
/// <summary> /// Callback from PlayFab when the receipt validation has been successful. /// Products will be granted and transactions confirmed. /// </summary> public void OnValidationResult(PlayFabResultCommon result) { Product p = IAPManager.controller.products.WithStoreSpecificID(result.CustomData as string); if (p == null) { return; } IAPManager.controller.ConfirmPendingPurchase(p); //successful response, verified transaction if (IAPManager.isDebug) { Debug.Log(p.definition.storeSpecificId + " verification success."); } IAPManager.GetInstance().PurchaseVerified(p.definition.id); }
//when the window gets opened void OnEnable() { //reconnect reference if (iapEditor == null) iapEditor = this; //get reference to the shop and cache it shop = GameObject.FindObjectOfType(typeof(ShopManager)) as ShopManager; script = FindIAPManager(); //could not get prefab, non-existent? if (script == null) return; if (shop) RemoveContainerConnections(); }
//locate IAP Manager prefab in the project public static IAPManager FindIAPManager() { GameObject obj = Resources.Load("IAP Manager") as GameObject; if (obj != null && PrefabUtility.GetPrefabType(obj) == PrefabType.Prefab) { //try to get IAP Manager component and return it IAPManager iap = obj.GetComponent(typeof(IAPManager)) as IAPManager; if (iap != null) { IAPPrefab = obj; return(iap); } } return(null); }
/// <summary> /// removes all data set by DBManager. /// Should be used for testing purposes only /// </summary> public static void ClearAll() { PlayerPrefs.DeleteKey(instance.prefsKey); PlayerPrefs.DeleteKey(instance.remoteKey); instance.gameData = null; string[] ids = IAPManager.GetIAPKeys(); for (int i = 0; i < ids.Length; i++) { string key = instance.idPrefix + ids[i]; if (instance.encrypt) { key = instance.Encrypt(key); } PlayerPrefs.DeleteKey(key); } }
//when the window gets opened void OnEnable() { //reconnect reference if (iapEditor == null) { iapEditor = this; } //scene path currentScene = EditorApplication.currentScene; //get reference to the shop and cache it shop = GameObject.FindObjectOfType(typeof(ShopManager)) as ShopManager; script = FindIAPManager(); //could not get prefab, non-existent? if (script == null) { return; } if (shop) { RemoveContainerConnections(); } //set current currency index from -1 to first one, //if currencies were specified if (script.currency.Count > 0) { currencyIndex = 0; } //get current platform variable and set selected index string currentPlatform = script.androidPlatform.ToString(); for (int i = 0; i < androidPlatformStrings.Length; i++) { if (androidPlatformStrings[i] == currentPlatform) { androidPlatform = i; break; } } }
/// <summary> /// created by the IAPManager /// </summary> public IAPStoreAssets(IAPManager script) { this.script = script; Init(); }
//when the window gets opened void OnEnable() { //reconnect reference if (iapEditor == null) iapEditor = this; //get reference to the shop and cache it shop = GameObject.FindObjectOfType(typeof(ShopManager)) as ShopManager; script = FindIAPManager(); //could not get prefab, non-existent? if (script == null) return; if (shop) RemoveContainerConnections(); //set current currency index from -1 to first one, //if currencies were specified if (script.currency.Count > 0) currencyIndex = 0; }
// initialize IAPs, billing systems and database, // as well as shop components in this order void Awake() { //make sure we keep one instance of this script in the game if (instance) { Destroy(gameObject); return; } DontDestroyOnLoad(this); //ensure that we are always developing on a mobile platform, //otherwise print a warning #if !UNITY_ANDROID && !UNITY_IPHONE Debug.LogWarning("IAPManager: Detected non-mobile platform. Purchases for real money are" + " not supported on this platform. Please switch to iOS/Android."); #endif //set static reference instance = this; //populate IAP dictionary and arrays with product ids InitIds(); //map Prime31 IAP handler delegates to fire corresponding methods #if UNITY_ANDROID GoogleIABManager.billingSupportedEvent += RequestProductData; GoogleIABManager.billingNotSupportedEvent += BillingNotSupported; GoogleIABManager.queryInventorySucceededEvent += ProductDataReceived; GoogleIABManager.queryInventoryFailedEvent += BillingNotSupported; GoogleIABManager.purchaseSucceededEvent += PurchaseSucceeded; GoogleIABManager.purchaseFailedEvent += PurchaseFailed; GoogleIABManager.consumePurchaseSucceededEvent += ConsumeSucceeded; GoogleIABManager.consumePurchaseFailedEvent += PurchaseFailed; //initializes Google's billing system //by passing in your google dev key if (!string.IsNullOrEmpty(googleStoreKey)) GoogleIAB.init(googleStoreKey); else Debug.LogWarning("IAPManager: Google Store Key missing on IAP Manager prefab. " + "Purchases for real money won't be supported on the device."); //enables high detail logging to the console, //do not comment out in production versions! //this is for testing only GoogleIAB.enableLogging(false); #elif UNITY_IPHONE StoreKitManager.productListReceivedEvent += ProductDataReceived; StoreKitManager.productListRequestFailedEvent += BillingNotSupported; StoreKitManager.purchaseSuccessfulEvent += PurchaseSucceeded; StoreKitManager.purchaseFailedEvent += PurchaseFailed; StoreKitManager.purchaseCancelledEvent += PurchaseFailed; StoreKitManager.restoreTransactionsFinishedEvent += RestoreSucceeded; StoreKitManager.restoreTransactionsFailedEvent += RestoreFailed; //initializes Apple's billing system //when parental controls aren't active if(StoreKitBinding.canMakePayments()) RequestProductData(); else BillingNotSupported("Apple App Store not available."); #endif //initialize database, remote and shop managers GetComponent<DBManager>().Init(); StartCoroutine(RemoteDownload()); OnLevelWasLoaded(-1); }
// initialize IAPs, billing systems and database, // as well as shop components in this order void Awake() { //make sure we keep one instance of this script in the game if (instance) { Destroy(gameObject); return; } DontDestroyOnLoad(this); isDebug = Debug.isDebugBuild; //set static reference instance = this; //populate IAP dictionary and arrays with product ids InitIds(); //initialize database, remote and shop managers GetComponent<IAPListener>().Init(); GetComponent<DBManager>().Init(); StartCoroutine(RemoteDownload()); OnLevelWasLoaded(-1); }
// initialize IAPs and subscribe to important events void Awake() { //make sure we keep one instance of this script in the game if (instance) { Destroy(gameObject); return; } DontDestroyOnLoad(this); //set static reference instance = this; //populate IAP dictionary and arrays with product ids InitIds(); //map delegates to fire corresponding methods StoreEvents.OnUnexpectedStoreError += BillingNotSupported; StoreEvents.OnMarketItemsRefreshFinished += ProductDataReceived; StoreEvents.OnMarketPurchaseCancelled += PurchaseFailed; StoreEvents.OnRestoreTransactionsFinished += RestoreSucceeded; }
#pragma warning restore 0414 // initialize IAPs, billing systems and database, // as well as shop components in this order void Awake() { //make sure we keep one instance of this script in the game if (instance) { Destroy(gameObject); return; } DontDestroyOnLoad(this); isDebug = Debug.isDebugBuild; //set static reference instance = this; //populate IAP dictionary and arrays with product ids InitIds(); var module = StandardPurchasingModule.Instance(); var builder = ConfigurationBuilder.Instance(module); RequestProductData(builder); builder.Configure<IGooglePlayConfiguration>().SetPublicKey(googleStoreKey); if(isDebug) { builder.Configure<IMicrosoftConfiguration>().useMockBillingSystem = true; // Write out our Amazon Sandbox JSON file. // This has no effect when the Amazon billing service is not in use. builder.Configure<IAmazonConfiguration>().WriteSandboxJSON(builder.products); // Enable "developer mode" for purchases, not requiring real-world money builder.Configure<ISamsungAppsConfiguration>().SetMode(SamsungAppsMode.AlwaysSucceed); } // Now we're ready to initialize Unity IAP. UnityPurchasing.Initialize(this, builder); //initialize database, remote and shop managers GetComponent<IAPListener>().Init(); GetComponent<DBManager>().Init(); StartCoroutine(RemoteDownload()); validator = GetComponent<ReceiptValidator>(); #if UNITY_5_4_OR_NEWER SceneManager.sceneLoaded += OnSceneWasLoaded; #endif OnSceneLoaded(); }