Example #1
0
        // set product to purchased after successful verification (or without)
        // For non consumable IAPs or subscriptions, alter database entry
        public void PurchaseVerified(string id)
        {
            if (!IAPObjects.ContainsKey(id))
            {
                id = GetIAPIdentifier(id);
            }
            if (!IAPObjects.ContainsKey(id))
            {
                return;
            }
            IAPObject obj = IAPObjects[id];

            //don't continue if the product is already purchased,
            //for example if we just want to verify an existing product again
            if (DBManager.isPurchased(id))
            {
                return;
            }
            if (obj.type != ProductType.Consumable)
            {
                DBManager.SetToPurchased(id);
            }

            purchaseSucceededEvent(id);
        }
Example #2
0
        /// <summary>
        /// Restore already purchased user's transactions for non consumable IAPs.
        /// For Android we use the received list for detecting previous purchases.
        /// </summary>
        public static void RestoreTransactions()
        {
                        #if UNITY_IOS
            extensions.GetExtension <IAppleExtensions>().RestoreTransactions(OnTransactionsRestored);
                        #else
            Product[] purchasedProducts = controller.products.all;
            foreach (Product product in purchasedProducts)
            {
                string id = product.definition.id;
                if (DBManager.isPurchased(id) || product.definition.type == ProductType.Consumable ||
                    !product.hasReceipt || String.IsNullOrEmpty(product.receipt))
                {
                    continue;
                }

                DBManager.SetToPurchased(id);
            }

            OnTransactionsRestored(true);
            #endif

            //update ShopManager GUI items
            if (ShopManager.GetInstance())
            {
                ShopManager.SetItemState();
            }
        }
Example #3
0
        /// <summary>
        /// restore already purchased user's transactions for non consumable iaps.
        /// For Android/WP8 we use the received list for detecting previous purchases
        /// </summary>
        public static void RestoreTransactions()
        {
                        #if UNITY_IPHONE
            OpenIAB.restoreTransactions();
                        #elif UNITY_ANDROID || UNITY_WP8
            if (inventory == null)
            {
                RestoreFailed("Restoring transactions failed. Please try again.");
                return;
            }

            List <string> prods = inventory.GetAllOwnedSkus();
            for (int i = 0; i < prods.Count; i++)
            {
                string id = GetIAPIdentifier(prods[i]);
                if (!DBManager.isPurchased(id))
                {
                    DBManager.SetToPurchased(id);
                }
            }
            RestoreSucceeded();
                        #endif

            //update ShopManager GUI items
            if (ShopManager.GetInstance())
            {
                ShopManager.SetItemState();
            }
        }
Example #4
0
        /// <summary>
        /// Overload for purchasing virtual product based on its product identifier.
        /// </summary>
        public static void PurchaseProduct(IAPObject obj)
        {
            string productId = obj.id;

            //product is set to already owned, do nothing
            if (DBManager.isPurchased(productId))
            {
                OnPurchaseFailed("Product already purchased.");
                return;
            }

            //check whether the player has enough funds
            bool didSucceed = DBManager.VerifyVirtualPurchase(obj);

            if (isDebug)
            {
                Debug.Log("Purchasing virtual product " + productId + ", result: " + didSucceed);
            }
            //on success, non-consumables are saved to the database. This automatically
            //saves the new substracted fund value, then and fire the succeeded event
            if (didSucceed)
            {
                if (obj.type != ProductType.Consumable)
                {
                    DBManager.SetToPurchased(productId);
                }
                purchaseSucceededEvent(productId);
            }
            else
            {
                OnPurchaseFailed("Insufficient funds.");
            }
        }
Example #5
0
        /// <summary>
        /// purchase non-consumable virtual product based on its product id
        /// </summary>
        public static void PurchaseNonconsumableVirtualProduct(string productId)
        {
            //if already owned, do nothing
            if (DBManager.isPurchased(productId))
            {
                PurchaseFailed("Product already purchased.");
                return;
            }

            //check whether the player has enough funds
            bool didSucceed = DBManager.VerifyVirtualPurchase(GetIAPObject(productId));

            if (instance.debug)
            {
                Debug.Log("purchasing non-consumable virtual product " + productId + " result: " + didSucceed);
            }
            //on success, non-consumables are being saved to the database
            //this automatically saves the new substracted fund value to the database
            //and fire the succeeded event
            if (didSucceed)
            {
                DBManager.SetToPurchased(productId);
                purchaseSucceededEvent(productId);
            }
            //otherwise show fail message
            else
            {
                PurchaseFailed("Insufficient funds.");
            }
        }
Example #6
0
        // set product to purchased after successful verification (or without)
        // Consumable IAPs must be consumed
        // For non consumable IAPs or subscriptions, alter database entry
        private void PurchaseVerified(string id)
        {
            if (!IAPObjects.ContainsKey(id))
            {
                return;
            }
            IAPObject obj = IAPObjects[id];

            if (obj.type == IAPType.consumable)
            {
                OpenIAB.consumeProduct(inventory.GetPurchase(obj.GetIdentifier()));                 //local id
                return;
            }

            //don't continue if the product is already purchased,
            //for example if we just want to verify an existing product again
            if (DBManager.isPurchased(id))
            {
                return;
            }

            if (obj.type == IAPType.nonConsumable || obj.type == IAPType.subscription)
            {
                DBManager.SetToPurchased(id);
            }

            purchaseSucceededEvent(id);
        }
Example #7
0
        /// <summary>
        /// restore already purchased user's transactions for non consumable iaps.
        /// For Android we use the received list for detecting previous purchases
        /// </summary>
        public static void RestoreTransactions()
        {
            #if UNITY_IPHONE
            StoreKitBinding.restoreCompletedTransactions();
            #elif UNITY_ANDROID
            if (prods == null)
            {
                RestoreFailed("Restoring transactions failed. Please try again.");
                return;
            }

            for (int i = 0; i < prods.Count; i++)
            {
                string id = GetIAPIdentifier(prods[i].productId);
                if (!DBManager.isPurchased(id))
                {
                    DBManager.SetToPurchased(id);
                }
            }
            RestoreSucceeded();
            #endif

            //update ShopManager GUI items
            if (ShopManager.GetInstance())
            {
                ShopManager.SetItemState();
            }
        }
        /// <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();
                    }
                }
            }
        }
Example #9
0
        // check for purchases on online servers at billing initialization.
        // If a purchase is not registered, set local purchase state back to false
        private void VerifyReceipts()
        {
            //get list of old purchases: on iOS the saved transactions,
            //on Android we use the old purchases list received from Google
            if (inventory == null || inventory.GetAllPurchases().Count == 0)
            {
                return;
            }

            //loop over all IAP items to check if a valid receipt exists
            for (int i = 0; i < ids.Length; i++)
            {
                //cache IAP id,
                //only verify purchased items
                string localId  = ids[i];
                string globalId = GetIAPIdentifier(localId);
                if (DBManager.isPurchased(globalId))
                {
                    //initialize item as faked and loop over receipts
                    bool     faked   = true;
                    Purchase receipt = inventory.GetPurchase(localId);

                    if (receipt != null)
                    {
                        //we found a receipt for this product on the device,
                        //unset fake purchase and let our external
                        //server decide what happens with this transaction
                        faked = false;
                        MakeRequest(receipt);
                        break;
                    }

                    //we haven't found a receipt for this item, yet it is
                    //set to purchased. This can't be, maybe our external server
                    //response or the database has been hacked with fake data
                    if (faked)
                    {
                        IAPItem item = null;
                        if (ShopManager.GetInstance())
                        {
                            item = ShopManager.GetIAPItem(globalId);
                        }
                        if (item)
                        {
                            item.Purchased(false);
                        }
                        DBManager.RemovePurchased(globalId);
                    }
                }
            }
        }
Example #10
0
        /// <summary>
        /// Returns the next unpurchased upgrade id of a product.
        /// </summary>
        public static string GetNextUpgrade(string productId)
        {
            string    id  = GetCurrentUpgrade(productId);
            IAPObject obj = GetIAPObject(id);

            if (!DBManager.isPurchased(id) || obj == null || string.IsNullOrEmpty(obj.req.nextId))
            {
                return(id);
            }
            else
            {
                return(obj.req.nextId);
            }
        }
Example #11
0
        /// <summary>
        /// Returns the last purchased upgrade id of a product,
        /// or the main product itself if it hasn't been purchased yet.
        /// </summary>
        public static string GetCurrentUpgrade(string productId)
        {
            if (!DBManager.isPurchased(productId))
            {
                return(productId);
            }

            string        id       = productId;
            List <string> upgrades = GetIAPUpgrades(productId);

            for (int i = upgrades.Count - 1; i >= 0; i--)
            {
                if (DBManager.isPurchased(upgrades[i]))
                {
                    id = upgrades[i];
                    break;
                }
            }

            return(id);
        }
Example #12
0
        private void OnProductsRetrieved(BillingResult result)
        {
            if (!result.IsSuccess)
            {
                OnSetupFailed(result.Response + ", " + result.Message);
                return;
            }

            AndroidInventory              inventory = AndroidInAppPurchaseManager.Client.Inventory;
            List <GoogleProductTemplate>  list      = inventory.Products;
            List <GooglePurchaseTemplate> purchases = inventory.Purchases;

            string globalId = null;
            string storeId  = null;

            for (int i = 0; i < list.Count; i++)
            {
                storeId  = list[i].SKU;
                globalId = IAPManager.GetIAPIdentifier(storeId);

                if (!products.ContainsKey(globalId))
                {
                    products.Add(globalId, new ProductDescription(storeId, new ProductMetadata(list[i].LocalizedPrice,
                                                                                               list[i].Title, list[i].Description,
                                                                                               list[i].PriceCurrencyCode, (decimal)list[i].Price)));
                }

                //check for non-consumed consumables
                if (storeId in purchases)
                {
                    IAPObject obj = IAPManager.GetIAPObject(IAPManager.GetIAPIdentifier(purchases[i].SKU));
                    if (obj != null && obj.type == ProductType.Consumable)
                    {
                        AndroidInAppPurchaseManager.Client.Consume(purchases[i].SKU);
                        continue;
                    }
                }

                bool storeResult = inventory.IsProductPurchased(storeId);
                if (storeResult == true)
                {
                    products[globalId] = new ProductDescription(storeId, products[globalId].metadata, inventory.GetPurchaseDetails(storeId).Token, inventory.GetPurchaseDetails(storeId).OrderId);
                }

                #if !UNITY_EDITOR
                //auto restore products in case database does not match
                if (storeResult != DBManager.isPurchased(globalId))
                {
                    if (storeResult)
                    {
                        DBManager.SetToPurchased(globalId);
                    }
                    else
                    {
                        DBManager.RemovePurchased(globalId);
                    }
                }
                #endif
            }

            callback.OnProductsRetrieved(products.Values.ToList());
        }
Example #13
0
        public void OnPurchaseSucceeded(IOSStoreKitResult item)
        {
            switch (item.State)
            {
            case InAppPurchaseState.Deferred:
                return;

            case InAppPurchaseState.Restored:
                ProductDefinition definition = definitions.FirstOrDefault(x => x.storeSpecificId == item.ProductIdentifier);
                if (definition == null || definition.type == ProductType.Subscription || DBManager.isPurchased(definition.id))
                {
                    return;
                }
                break;

            case InAppPurchaseState.Failed:
                OnPurchaseFailed(item.Error.Message, item.Error.Code);
                return;
            }

            string transactionId = item.TransactionIdentifier;

            #if UNITY_EDITOR
            //allow for multiple test purchases with unique transactions
            transactionId = (System.DateTime.UtcNow - new System.DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc)).TotalSeconds.ToString();
            #endif

            callback.OnPurchaseSucceeded(item.ProductIdentifier, item.Receipt, transactionId);
        }
Example #14
0
        // handles an online verification request and response from
        // our external server. www.text can returns true or false.
        // true: purchase verified, false: not verified (fake?) purchase
        IEnumerator WaitForRequest(Dictionary <string, string> dic)
        {
            //cache requested product id
            string id = dic["pid"];

            //build POST request with transaction data
            WWWForm form = new WWWForm();

            foreach (string key in dic.Keys)
            {
                form.AddField(key, dic[key]);
            }
            //create URL and execute until we have a respone
            WWW www = new WWW(serverUrl + verificationFileName, form);

            yield return(www);

            //check for URL errors
            if (www.error == null)
            {
                //we have a successful response from our server,
                //but it returned false (fake purchase)
                if (!bool.Parse(www.text))
                {
                    inventory.ErasePurchase(id);
                    if (debug)
                    {
                        Debug.Log("The receipt for '" + id + "' could not be verified: " + www.text);
                    }
                    //PurchaseFailed("The receipt for '" + id + "' could not be verified.");

                    id = GetIAPIdentifier(id);
                    //remove purchase from the database and update item state
                    if (DBManager.isPurchased(id))
                    {
                        IAPItem item = null;
                        if (ShopManager.GetInstance())
                        {
                            item = ShopManager.GetIAPItem(id);
                        }
                        if (item)
                        {
                            item.Purchased(false);
                        }
                        DBManager.RemovePurchased(id);
                    }
                    yield break;
                }
                else
                {
                    //successful response, verified transaction
                    if (debug)
                    {
                        Debug.Log(dic["pid"] + " verification success.");
                    }
                }
            }
            else
            {
                //we can't reach our external server, do nothing:
                //in this case we handle the purchase as without verification
                if (debug)
                {
                    Debug.Log("Verification URL error: " + www.text);
                }
            }

            id = GetIAPIdentifier(id);
            PurchaseVerified(id);
        }
Example #15
0
        // check for purchases on online servers at billing initialization.
        // If a purchase is not registered, set local purchase state back to false
        private void VerifyReceipts()
        {
            //get list of old purchases: on iOS the saved and filtered transactions (avoiding duplicates),
            //on Android we use the old purchases list received from Google
            #if UNITY_IPHONE
            List <StoreKitTransaction> prods = FilterTransactions(StoreKitBinding.getAllSavedTransactions());
            #endif
            if (prods == null || prods.Count == 0)
            {
                return;
            }

            //loop over all IAP items to check if a valid receipt exists
            for (int i = 0; i < ids.Length; i++)
            {
                //cache IAP id,
                //only verify purchased items
                string localId  = ids[i];
                string globalId = GetIAPIdentifier(localId);
                if (DBManager.isPurchased(globalId))
                {
                    //initialize item as faked and loop over receipts
                    bool faked = true;
                    for (int j = 0; j < prods.Count; j++)
                    {
                        //find corresponding transaction class
                        string identifier = "";
                        #if UNITY_IPHONE
                        StoreKitTransaction purchase = prods[j];
                        identifier = purchase.productIdentifier;
                        #elif UNITY_ANDROID
                        GooglePurchase purchase = prods[j];
                        identifier = purchase.productId;
                        #endif
                        if (identifier == localId)
                        {
                            //we found a receipt for this product on the device,
                            //unset fake purchase and let our external
                            //server decide what happens with this transaction
                            faked = false;
                            MakeRequest(purchase);
                            break;
                        }
                    }
                    //we haven't found a receipt for this item, yet it is
                    //set to purchased. This can't be, maybe our external server
                    //response or the database has been hacked with fake data
                    if (faked)
                    {
                        IAPItem item = null;
                        if (ShopManager.GetInstance())
                        {
                            item = ShopManager.GetIAPItem(globalId);
                        }
                        if (item)
                        {
                            item.Purchased(false);
                        }
                        DBManager.RemovePurchased(globalId);
                    }
                }
            }
        }