// 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); } } } }
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()); }
// 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); }
// 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); } } } }