/// <summary> /// Gets the Apple App receipt. This method only works if receipt validation is enabled. /// </summary> /// <returns>The Apple App receipt.</returns> public static AppleReceipt GetAppleAppReceipt() { if (!IsInitialized()) { Debug.Log("Couldn't get Apple app receipt: In-App Purchasing is not initialized."); return(null); } if (!EM_Settings.InAppPurchasing.ValidateAppleReceipt) { Debug.Log("Couldn't get Apple app receipt: Please enable Apple receipt validation."); return(null); } // Note that the code is disabled in the editor for it to not stop the EM editor code (due to ClassNotFound error) // from recreating the dummy AppleTangle class if they were inadvertently removed. #if UNITY_IOS && !UNITY_EDITOR // Get a reference to IAppleConfiguration during IAP initialization. var appleConfig = sBuilder.Configure <IAppleConfiguration>(); var receiptData = System.Convert.FromBase64String(appleConfig.appReceipt); AppleReceipt receipt = new AppleValidator(AppleTangle.Data()).Validate(receiptData); return(receipt); #else Debug.Log("Getting Apple app receipt is only available on iOS."); return(null); #endif }
/// <summary> /// Gets introductory offer details. /// Includes Free Trial. /// </summary> /// <param name="productID">Product ID</param> /// <param name="groupProductIDs">Group products that productID belongs to. /// If empty or null, assume productID is in its own group.</param> /// <returns>Offer details if exists.</returns> public UniTask <IntroductoryOffer> GetIntroductoryOfferDetailsAsync(string productID, string[] groupProductIDs = null) { // Determine if product exists. var products = apple.GetProductDetails(); if (products == null || !products.ContainsKey(productID)) { // No product available. return(UniTask.FromResult <IntroductoryOffer>(null)); } // Get product details. IntroductoryOffer offer = null; try { offer = new IOSIntroductoryOfferFactory(products[productID]).Make(); } catch (InvalidOfferException) { // Invalid offer. return(UniTask.FromResult <IntroductoryOffer>(null)); } catch (Exception e) { // Invalid json! Debug.LogWarning($"Invalid product data detected! {e.Message}"); return(UniTask.FromResult <IntroductoryOffer>(null)); } try { var receiptData = System.Convert.FromBase64String(appleConfig.appReceipt); AppleReceipt receipt = new AppleValidator(appleTangleData).Validate(receiptData); if (receipt == null || receipt.inAppPurchaseReceipts == null) { // no previous subscription purchased. return(UniTask.FromResult(offer)); } if (groupProductIDs == null || groupProductIDs.Length == 0) { groupProductIDs = new string[] { productID }; } var prevCampaignPurchase = receipt.inAppPurchaseReceipts .FirstOrDefault(r => groupProductIDs.Contains(r.productID) && (r.isFreeTrial != 0 || r.isIntroductoryPricePeriod != 0)); if (prevCampaignPurchase != null) { // user already used free trial or introductory offer. return(UniTask.FromResult <IntroductoryOffer>(null)); } } catch { // unable to validate receipt or unable to access. return(UniTask.FromResult <IntroductoryOffer>(null)); } return(UniTask.FromResult(offer)); }
PurchaseProcessingResult IStoreListener.ProcessPurchase(PurchaseEventArgs e) { DebugLog("Processing a purchase"); // receipt validation tangle data not available. if (appleTangleData == null) { OnPurchased?.Invoke(PurchaseResponse.Ok, e.purchasedProduct); onRestored?.Invoke(PurchaseResponse.Ok); onRestored = null; return(PurchaseProcessingResult.Complete); } // validate receipt. try { var receiptData = System.Convert.FromBase64String(appleConfig.appReceipt); AppleReceipt receipt = new AppleValidator(appleTangleData).Validate(receiptData); #if DEBUG_IAP foreach (AppleInAppPurchaseReceipt receipts in receipt.inAppPurchaseReceipts) { var sb = new StringBuilder("Purchase Receipt Details:"); sb.Append($"\n Original Transaction ID: {receipts.originalTransactionIdentifier}"); sb.Append($"\n Intro Price Period: {receipts.isIntroductoryPricePeriod}"); sb.Append($"\n Product ID: {receipts.productID}"); sb.Append($"\n Product type: {receipts.productType}"); sb.Append($"\n Quantity: {receipts.quantity}"); sb.Append($"\n Original Transaction ID: {receipts.originalTransactionIdentifier}"); sb.Append($"\n Original Purchase Date: {receipts.originalPurchaseDate}"); sb.Append($"\n Purchase Date: {receipts.purchaseDate}"); sb.Append($"\n Cancellation Date: {receipts.cancellationDate}"); sb.Append($"\n Subsc Expiration Date: {receipts.subscriptionExpirationDate}"); sb.Append($"\n Free trial: {receipts.isFreeTrial}"); DebugLog(sb); } #endif OnPurchased?.Invoke(PurchaseResponse.Ok, e.purchasedProduct); onRestored?.Invoke(PurchaseResponse.Ok); onRestored = null; } catch (IAPSecurityException err) { Debug.Log($"Invalid receipt or security exception: {err.Message}"); OnPurchased?.Invoke(PurchaseResponse.InvalidReceipt, e.purchasedProduct); onRestored?.Invoke(PurchaseResponse.InvalidReceipt); onRestored = null; } catch { OnPurchased?.Invoke(PurchaseResponse.InvalidReceipt, e.purchasedProduct); onRestored?.Invoke(PurchaseResponse.InvalidReceipt); onRestored = null; } return(PurchaseProcessingResult.Complete); }