com.guru.unity.sdk.core/Runtime/GuruIAP/Runtime/Code/IAPServiceBase.cs

1010 lines
34 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

namespace Guru
{
using System;
using System.Linq;
using UnityEngine;
using UnityEngine.Purchasing;
using UnityEngine.Purchasing.Security;
using System.Collections.Generic;
using Firebase.Crashlytics;
public abstract class IAPServiceBase<T>: IStoreListener where T: IAPServiceBase<T> , new()
{
public static readonly int OrderRequestTimeout = 10;
public static readonly int OrderRequestRetryTimes = 3;
#region 属性定义
private const string Tag = "[IAP]";
private const string DefaultCategory = "Store";
private static bool _showLog;
private ConfigurationBuilder _configBuilder; // 商店配置创建器
private IStoreController _storeController;
private IExtensionProvider _storeExtensionProvider;
private IAppleExtensions _appleExtensions;
private IGooglePlayStoreExtensions _googlePlayStoreExtensions;
private CrossPlatformValidator _validator;
private Dictionary<string, ProductInfo> _products;
protected Dictionary<string, ProductInfo> Products => _products;
public bool IsInitialized => _storeController != null && _storeExtensionProvider != null;
private Product _curPurchasingProduct = null;
private IAPModel _model;
/// <summary>
/// 是否是首次购买
/// </summary>
public int PurchaseCount
{
get => _model.PurchaseCount;
set => _model.PurchaseCount = value;
}
/// <summary>
/// 是否是首个IAP
/// </summary>
public bool IsFirstIAP => PurchaseCount == 0;
private byte[] _googlePublicKey;
private byte[] _appleRootCert;
/// <summary>
/// 服务初始化回调
/// </summary>
public event Action<bool> OnInitResult;
/// <summary>
/// 恢复购买回调
/// </summary>
public event Action<bool, string> OnRestored;
public event Action<string> OnBuyStart;
public event Action<string, bool> OnBuyEnd;
public event Action<string, string> OnBuyFailed;
public event Action<string, string, bool> OnGetProductReceipt;
#if UNITY_IOS
/// <summary>
/// AppStore 支付, 处理苹果支付延迟反应
/// </summary>
/// <returns></returns>
public Action<Product> OnAppStorePurchaseDeferred;
#endif
#endregion
#region 单利模式
protected static T _instance;
private static object _locker = new object();
public static T Instance
{
get
{
if (null == _instance)
{
lock (_locker)
{
_instance = Activator.CreateInstance<T>();
_instance.OnCreatedInit();
}
}
return _instance;
}
}
/// <summary>
/// 组件创建初始化
/// </summary>
protected virtual void OnCreatedInit()
{
Debug.Log("--- IAPService Init");
}
#endregion
#region 初始化
/// <summary>
/// 初始化支付服务
/// </summary>
public virtual void Initialize(bool showLog = false)
{
_showLog = showLog;
InitPurchasing();
}
/// <summary>
/// 带有校验器的初始化
/// </summary>
/// <param name="googlePublicKey"></param>
/// <param name="appleRootCert"></param>
/// <param name="showLog"></param>
public virtual void InitWithKeys(byte[] googlePublicKey, byte[] appleRootCert, bool showLog = false)
{
_googlePublicKey = googlePublicKey;
_appleRootCert = appleRootCert;
InitModel();
Initialize(showLog);
}
/// <summary>
/// 初始化支付插件
/// </summary>
protected virtual void InitPurchasing()
{
_configBuilder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
// 注入初始商品产品列表
var settings = GetProductSettings();
if (null != settings)
{
int len = settings.Length;
if(_products != null) _products.Clear();
_products = new Dictionary<string, ProductInfo>(len);
ProductSetting item;
IDs ids;
bool emptyIDs = false;
for (int i = 0; i < len; i++)
{
item = settings[i];
ids = new IDs();
if (!string.IsNullOrEmpty(item.GooglePlayProductId))
{
ids.Add(item.GooglePlayProductId, GooglePlay.Name);
}
else
{
#if UNITY_ADNROID
emptyIDs = true;
LogE($"[IAP] --- GoogleProductId is empty, please check the product setting: {item.ProductName}");
#endif
}
if (!string.IsNullOrEmpty(item.AppStoreProductId))
{
ids.Add(item.AppStoreProductId, AppleAppStore.Name);
}
else
{
#if UNITY_IOS
emptyIDs = true;
LogE($"[IAP] --- AppleProductId is empty, please check the product setting: {item.ProductName}");
#endif
}
if (emptyIDs)
{
continue;
}
_configBuilder.AddProduct(item.ProductId, item.Type, ids); // 添加商品
// 建立本地的商品信息列表
if (string.IsNullOrEmpty(item.Category)) item.Category = DefaultCategory;
_products[item.ProductId] = new ProductInfo() { Setting = item };
}
}
// 调用插件初始化
UnityPurchasing.Initialize(this, _configBuilder);
}
/// <summary>
/// 初始化成功
/// </summary>
/// <param name="controller"></param>
/// <param name="extensions"></param>
/// <exception cref="NotImplementedException"></exception>
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
LogI($"--- IAP Initialized Success");
_storeController = controller;
_storeExtensionProvider = extensions;
#if UNITY_IOS
_appleExtensions = extensions.GetExtension<IAppleExtensions>();
// On Apple platforms we need to handle deferred purchases caused by Apple's Ask to Buy feature.
// On non-Apple platforms this will have no effect; OnDeferred will never be called.
_appleExtensions.RegisterPurchaseDeferredListener(item =>
{
LogI("Purchase deferred: " + item.definition.id);
OnAppStorePurchaseDeferred?.Invoke(item);
});
#elif UNITY_ANDROID
_configBuilder.Configure<IGooglePlayConfiguration>().SetObfuscatedAccountId(IPMConfig.IPM_UID);
_googlePlayStoreExtensions = extensions.GetExtension<IGooglePlayStoreExtensions>();
// _googlePlayStoreExtensions.SetObfuscatedAccountId(IPMConfig.IPM_UID);
//添加安装游戏后第一次初试化进行恢复购买的回调 只有安卓才有
_googlePlayStoreExtensions.RestoreTransactions(OnRestoreHandle);
#endif
foreach (var item in _storeController.products.all)
{
if (!item.availableToPurchase)
{
continue;
}
if (_products.ContainsKey(item.definition.id))
{
_products[item.definition.id].SetProduct(item);
}
}
InitValidator(); // 初始化订单验证器
OnInitResult?.Invoke(true);
}
/// <summary>
/// 初始化失败
/// </summary>
/// <param name="error"></param>
/// <exception cref="NotImplementedException"></exception>
public void OnInitializeFailed(InitializationFailureReason error)
{
LogE($"--- IAP Initialized Fail: {error}");
OnInitResult?.Invoke(false);
}
/// <summary>
/// 初始化失败
/// </summary>
/// <param name="error"></param>
/// <param name="message"></param>
/// <exception cref="NotImplementedException"></exception>
public void OnInitializeFailed(InitializationFailureReason error, string message)
{
LogE($"--- IAP Initialized Fail: {error} msg: {message}");
OnInitResult?.Invoke(false);
}
#endregion
#region 数据查询
// <summary>
/// 获取商品Info
/// </summary>
/// <param name="productName">商品名称</param>
/// <returns></returns>
public ProductInfo GetInfo(string productName)
{
if(null == Products || Products.Count == 0 ) return null;
return Products.Values.FirstOrDefault(c => c.Name == productName);
}
/// <summary>
/// 通过商品ID获取对应的信息
/// </summary>
/// <param name="productId">商品ID</param>
/// <returns></returns>
public ProductInfo GetInfoById(string productId)
{
if(null == Products || Products.Count == 0 ) return null;
return Products.Values.FirstOrDefault(c => c.Id == productId);
}
/// <summary>
/// 获取道具价格
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public double GetProductPrice(string name)
{
if (_storeController == null || _storeController.products == null)
{
return Fallback();
}
ProductInfo info = GetInfo(name);
var product = _storeController.products.WithID(info.Id);
if (product == null)
return Fallback();
return (double)product.metadata.localizedPrice;
double Fallback()
{
ProductInfo info = GetInfo(name);
return info?.Price ?? 0.0;
}
}
/// <summary>
/// 获取道具价格(带单位 $0.01
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public string GetProductPriceString(string name)
{
if (_storeController == null || _storeController.products == null)
{
return Fallback();
}
ProductInfo info = GetInfo(name);
var product = _storeController.products.WithID(info.Id);
if (product == null)
return Fallback();
return product.metadata.localizedPriceString;
string Fallback()
{
ProductInfo info = GetInfo(name);
var pr = info?.Price ?? 0.0;
return "$" + pr;
}
}
/// <summary>
/// 获取 IAP 内置商品
/// </summary>
/// <param name="productName"></param>
/// <returns></returns>
public Product GetProduct(string productName)
{
if (_storeController != null && _storeController.products != null)
{
var info = GetInfo(productName);
if (info != null)
{
return _storeController.products.WithID(info.Id);
}
Debug.LogError($"[IAP] --- can't find <ProductInfo> with name {productName}");
}
// 商品不存在则返回 NULL
Debug.LogError($"[IAP] --- _storeController is null or products is null or products.all.Length == 0");
return null;
}
/// <summary>
/// 当前的商品是否已经持有收据了
/// </summary>
/// <param name="productName"></param>
/// <returns></returns>
public bool IsProductHasReceipt(string productName)
{
var product = GetProduct(productName);
if (product != null) return product.hasReceipt;
return false;
}
#endregion
#region 订单验证器
/// <summary>
/// 是否支持订单校验
/// </summary>
/// <returns></returns>
private bool IsCurrentStoreSupportedByValidator()
=> IsGooglePlayStoreSelected() || IsAppleAppStoreSelected();
/// <summary>
/// Google 商店支持
/// </summary>
/// <returns></returns>
private bool IsGooglePlayStoreSelected()
{
var currentAppStore = StandardPurchasingModule.Instance().appStore;
return currentAppStore == AppStore.GooglePlay;
}
/// <summary>
/// Apple 商店支持
/// </summary>
/// <returns></returns>
private bool IsAppleAppStoreSelected()
{
var currentAppStore = StandardPurchasingModule.Instance().appStore;
return currentAppStore == AppStore.AppleAppStore || currentAppStore == AppStore.MacAppStore;
}
/// <summary>
/// 初始化订单校验器
/// </summary>
protected virtual void InitValidator()
{
if (IsCurrentStoreSupportedByValidator())
{
try
{
if (_googlePublicKey != null && _appleRootCert != null)
{
_validator = new CrossPlatformValidator(_googlePublicKey, _appleRootCert, Application.identifier);
}
else
{
Crashlytics.LogException(new Exception($"[IAP] Init Validator failed -> googlePublicKey: {_googlePublicKey} appleRootCert: {_appleRootCert}"));
}
}
catch (NotImplementedException exception)
{
LogE("Cross Platform Validator Not Implemented: " + exception);
}
}
}
#endregion
#region 恢复购买
/// <summary>
/// 恢复购买
/// </summary>
/// <param name="success"></param>
/// <param name="msg"></param>
protected virtual void OnRestoreHandle(bool success, string msg)
{
LogI($"--- Restore complete: {success}: msg:{msg}" );
if (success)
{
bool isIAPUser = false;
// 扫描所有商品, 追加用户属性
for (int i = 0; i < _storeController.products.all.Length; i++)
{
var product = _storeController.products.all[i];
if (product.hasReceipt)
{
isIAPUser = true;
}
}
SetIsIAPUser(isIAPUser);
}
OnRestored?.Invoke(success, msg);
}
/// <summary>
/// 恢复购买道具
/// </summary>
public virtual void Restore()
{
if (!IsInitialized) return;
#if UNITY_IOS
_appleExtensions.RestoreTransactions(OnRestoreHandle);
#elif UNITY_ANDROID
_googlePlayStoreExtensions.RestoreTransactions(OnRestoreHandle);
#endif
}
#endregion
#region 购买流程
/// <summary>
/// 购买商品
/// </summary>
/// <param name="productName"></param>
public virtual T Buy(string productName)
{
if (!IsInitialized)
{
LogE("Buy FAIL. Not initialized.");
OnBuyEnd?.Invoke(productName, false);
return (T)this;
}
ProductInfo info = GetInfo(productName);
if (info == null)
{
LogE($"Buy FAIL. No product with name: {productName}");
OnBuyEnd?.Invoke(productName, false);
return (T)this;
}
Product product = _storeController.products.WithID(info.Setting.ProductId);
if (product != null && product.availableToPurchase)
{
#if UNITY_ANDROID
_configBuilder
.Configure<IGooglePlayConfiguration>()
.SetObfuscatedAccountId(IPMConfig.IPM_UID);
#endif
_storeController.InitiatePurchase(product);
Analytics.IAPClick(info?.Category??"none", product.definition.id);
Analytics.IAPImp(DefaultCategory, product.definition.id);
_curPurchasingProduct = product;
OnBuyStart?.Invoke(productName);
return (T)this;
}
// 找不到商品
LogE($"Can't find product by name: {productName}, pay canceled.");
OnPurchaseOver(false, productName);
OnBuyEnd?.Invoke(productName, false);
return (T)this;
}
/// <summary>
/// 处理支付流程
/// </summary>
/// <param name="purchaseEvent"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent)
{
string productId = purchaseEvent.purchasedProduct.definition.id;
ProductInfo info = GetInfoById(productId);
bool success = false;
if (null != info)
{
if (IsFirstIAP) Analytics.FirstIAP(info.Id, info.Price, info.CurrencyCode); // 上报首次支付打点
Analytics.ProductIAP(info.Id,info.Id, info.Price, info.CurrencyCode);
Analytics.IAPRetTrue(info.Category, info.Id, info.Price, info.CurrencyCode, info.Type, info.IsFree);
success = true;
SetIsIAPUser(success); // 设置用户属性标记
}
PurchaseCount++; // 记录支付次数
Debug.Log($"############ ProcessPurchase: PurchaseCount:{PurchaseCount}");
if (_curPurchasingProduct != null)
{
_curPurchasingProduct = null; // 只有实际发生购买后才会有订单上报. 启动时的 Restore 操作自动调用支付成功. 这里做一个判定, 过滤掉订单的物品
ReportPurchaseResult(purchaseEvent); // 支付结果上报
}
var pp = purchaseEvent.purchasedProduct;
if ( pp == null || string.IsNullOrEmpty(pp.receipt))
{
string msg = $"{Tag} --- Purchased product is null or has no receipt!!";
Debug.LogError(msg);
Crashlytics.LogException(new Exception(msg));
}
else
{
OnGetProductReceipt?.Invoke(pp.definition.id, pp.receipt, pp.appleProductIsRestored);
}
string productName = info?.Name ?? "NULL";
LogI($"{Tag} --- OnPurchaseSuccess :: purchase count: {PurchaseCount} productName: {productName}");
OnPurchaseOver(success, productName); // 支付成功处理逻辑
OnBuyEnd?.Invoke(productName, success);
return PurchaseProcessingResult.Complete; // 直接Consume 掉当前的商品
}
/// <summary>
/// 支付失败
/// </summary>
/// <param name="product"></param>
/// <param name="failureReason"></param>
/// <exception cref="NotImplementedException"></exception>
public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
{
string productId = product.definition.id;
ProductInfo info = GetInfoById(productId);
//上报点位,用户购买失败的原因
if (failureReason == PurchaseFailureReason.UserCancelled)
{
Analytics.IAPClose(info.Category, product.definition.id);
}
else
{
Analytics.IAPRetFalse(info.Category, product.definition.id, failureReason.ToString());
}
LogI($"{Tag} --- OnPurchaseFailed :: failureReason = {failureReason}");
// 失败的处理逻辑
OnPurchaseOver(false, info.Name);
OnBuyEnd?.Invoke(info.Name, false);
// 失败原因
OnBuyFailed?.Invoke(info.Name, failureReason.ToString());
}
/// <summary>
/// 获取商品的本地化价格字符串
/// 如果商品不存在或者 IAP 尚未初始化完成则显示 "Loading" 字样
/// </summary>
/// <param name="productName"></param>
/// <returns></returns>
public string GetLocalizedPriceString(string productName)
{
return GetInfo(productName)?.LocalizedPriceString ?? "Loading";
}
#endregion
#region Log 输出
/// <summary>
/// 日志输出
/// </summary>
/// <param name="msg"></param>
private static void LogI(object msg)
{
if (_showLog)
Debug.Log($"{Tag} {msg}");
}
private static void LogE(object msg)
{
if (_showLog)
Debug.LogError($"{Tag} {msg}");
}
private static void LogW(object msg)
{
if (_showLog)
Debug.LogWarning($"{Tag} {msg}");
}
#endregion
#region 实现接口
/// <summary>
/// 需要游戏侧继承并完成Blevel的取值上报
/// </summary>
/// <returns></returns>
protected abstract int GetBLevel();
/// <summary>
/// 获取商品品配置列表
/// </summary>
/// <returns></returns>
protected virtual ProductSetting[] GetProductSettings()
=> GuruSettings.Instance.Products;
/// <summary>
/// 支付回调
/// </summary>
/// <param name="success">是否成功</param>
/// <param name="productName">商品名称</param>
protected abstract void OnPurchaseOver(bool success, string productName);
#endregion
#region 支付上报逻辑
/// <summary>
/// 支付结果上报
/// </summary>
protected virtual void ReportPurchaseResult(PurchaseEventArgs args)
{
int blevel = GetBLevel();
int orderType = args.purchasedProduct.definition.type == ProductType.Subscription ? 1 : 0;
// Debug.Log($"############ ReportPurchaseResult: _validator:{_validator }");
if (_validator == null)
{
// Debug.Log($"############ --- Validator is null");
LogE($"{Tag} --- Validator is null. Report Order failed.");
Crashlytics.LogException(new Exception($"IAPService can not report order because Validator is null!"));
return;
}
try
{
// ----- 支付后的b_level上报逻辑
LogI($"--- Report b_level:[{blevel}] with product id:{args.purchasedProduct.definition.id} ");
#if UNITY_EDITOR
// Editor 不做上报逻辑
#elif UNITY_ANDROID
// Android 订单验证, 上报打点信息
var result = _validator.Validate(args.purchasedProduct.receipt);
string productID = orderType == 0 ? args.purchasedProduct.definition.id : "";
string subscriptionID = orderType == 1 ? args.purchasedProduct.definition.id : "";
LogI($"{Tag} --- Report Android IAP Order -> orderType:{orderType} productID:{productID} blevel:{blevel}");
foreach (var productReceipt in result)
{
if (productReceipt is GooglePlayReceipt google)
{
Debug.Log($"{Tag} --- Report Android IAP Order -> orderType:{orderType} productID:{productID} blevel:{blevel}");
// new GoogleOrderRequest(orderType, productID, subscriptionID, google.purchaseToken, blevel).SetTimeOut(5).Send();
ReportGoogleOrder(orderType, productID, subscriptionID, google.purchaseToken, blevel);
}
}
#elif UNITY_IOS
// iOS 订单验证, 上报打点信息
var jsonData = JsonMapper.ToObject(args.purchasedProduct.receipt);
string receipt = jsonData["Payload"].ToString();
// if (HasReceipt(receipt))
// {
// Debug.Log($"[IAP] Receipt has already reported: {receipt}");
// return;
// }
// AddReceipt(receipt);
// new AppleOrderRequest(orderType, args.purchasedProduct.definition.id, receipt,blevel).Send();
ReportAppleOrder(orderType, args.purchasedProduct.definition.id, receipt,blevel);
Debug.Log($"{Tag} --- Report iOS IAP Order -> orderType:{orderType} productID:{args.purchasedProduct.definition.id} blevel:{blevel}");
#endif
}
catch (Exception e)
{
LogE($" [IAPManager.RevenueUpload] got Exception: {e.Message}");
Crashlytics.LogException(new Exception($"[IAP] Unity report purchase data with b_level={blevel} got error: {e.Message}"));
}
}
#endregion
#region IOS Orders Collection
private HashSet<string> iOSReceipts;
public HashSet<string> IOSReceiptCollection
{
get
{
// 读取订单信息
if (iOSReceipts == null)
{
iOSReceipts = new HashSet<string>();
string raw = PlayerPrefs.GetString(nameof(IOSReceiptCollection), "");
if (!string.IsNullOrEmpty(raw))
{
var arr = raw.Split(',');
for (int i = 0; i < arr.Length; i++)
{
iOSReceipts.Add(arr[i]);
}
}
}
return iOSReceipts;
}
set
{
// 保存订单信息
iOSReceipts = value;
PlayerPrefs.SetString(nameof(IOSReceiptCollection), string.Join(",", iOSReceipts));
PlayerPrefs.Save();
}
}
/// <summary>
/// 添加订单信息
/// </summary>
/// <param name="receipt"></param>
public void AddReceipt(string receipt)
{
if (!HasReceipt(receipt))
{
IOSReceiptCollection.Add(receipt);
}
}
/// <summary>
/// 是否包含订单
/// </summary>
/// <param name="receipt"></param>
/// <returns></returns>
public bool HasReceipt(string receipt)
{
return IOSReceiptCollection.Contains(receipt);
}
#endregion
#region 用户标志位设置
/// <summary>
/// 标记是否为付费用户
/// </summary>
/// <param name="value"></param>
public static void SetIsIAPUser(bool value = true)
{
Analytics.SetUserProperty(Analytics.PropertyIsIAPUser, value ? "true" : "false");
}
#endregion
#region 数据初始化
private void InitModel()
{
_model = IAPModel.Load(); // 初始化 Model
// 启动时查询
if(_orderRequests == null)
_orderRequests = new Queue<RequestBase>(20);
// #if UNITY_EDITOR
// Debug.Log($"----- IAP Model init -----");
// #elif UNITY_ANDROID
#if UNITY_ANDROID
if (_model.HasUnreportedGoogleOrder)
{
foreach (var o in _model.googleOrders)
{
ReportGoogleOrder(o);
}
}
#elif UNITY_IOS
if (_model.HasUnreportedAppleOrder)
{
foreach (var o in _model.appleOrders)
{
ReportAppleOrder(o);
}
}
#endif
}
#endregion
#region 订单上报队列
private bool isOrderSending = false;
private Queue<RequestBase> _orderRequests = new Queue<RequestBase>(20);
/// <summary>
/// 上报 Google Order Request
/// </summary>
/// <param name="orderType"></param>
/// <param name="productId"></param>
/// <param name="subscriptionId"></param>
/// <param name="token"></param>
/// <param name="level"></param>
/// <param name="offerId"></param>
/// <param name="basePlanId"></param>
private void ReportGoogleOrder(int orderType, string productId, string subscriptionId, string token, int level,
string offerId = "", string basePlanId = "")
{
var request = GoogleOrderRequest.Build(orderType, productId, subscriptionId, token, level, offerId, basePlanId);
ReportNextOrder(request);
}
private void ReportGoogleOrder(GoogleOrderData data)
{
var request = GoogleOrderRequest.Build(data);
ReportNextOrder(request);
}
private void ReportAppleOrder(int orderType, string productId, string receipt, int level)
{
var request = AppleOrderRequest.Build(orderType, productId, receipt, level);
ReportNextOrder(request);
}
private void ReportAppleOrder(AppleOrderData data)
{
var request = AppleOrderRequest.Build(data);
ReportNextOrder(request);
}
private void ReportNextOrder(RequestBase request)
{
_orderRequests.Enqueue(request);
if(isOrderSending) return;
isOrderSending = true;
OnSendNextOrder();
}
/// <summary>
/// 上报下一个 Google 订单
/// </summary>
private void OnSendNextOrder()
{
if (_orderRequests != null && _orderRequests.Count > 0)
{
isOrderSending = true;
var request = _orderRequests.Dequeue();
GoogleOrderRequest go = request as GoogleOrderRequest;
AppleOrderRequest ao = request as AppleOrderRequest;
if (go != null && _model.IsTokenExists(go.token))
{
OnSendNextOrder();
return;
}
if( ao != null && _model.IsReceiptExist(ao.receipt))
{
OnSendNextOrder();
return;
}
request.SetTimeOut(OrderRequestTimeout)
.SetRetryTimes(OrderRequestRetryTimes)
.SetSuccessCallBack(() =>
{
if (go != null)
{
_model.AddToken(go.token);
_model.RemoveGoogleOrder(go.orderData);
}
else if (ao != null)
{
_model.AddReceipt(ao.receipt);
_model.RemoveAppleOrder(ao.orderData);
}
OnSendNextOrder();
})
.SetFailCallBack(() =>
{
if (go != null)
{
_model.AddGoogleOrder(go.orderData);
ReportGoogleOrderLost(go.orderData);
}
else if (ao != null)
{
_model.AddAppleOrder(ao.orderData);
ReportAppleOrderLost(ao.orderData);
}
OnSendNextOrder();
})
.Send();
}
else
{
isOrderSending = false;
}
}
private void ReportGoogleOrderLost(GoogleOrderData data)
{
Analytics.LogEvent("google_order_lost", new Dictionary<string, dynamic>()
{
["data"] = data.ToString(),
}, new Analytics.EventSetting()
{
EnableFirebaseAnalytics = true,
EnableFacebookAnalytics = true,
});
}
private void ReportAppleOrderLost(AppleOrderData data)
{
Analytics.LogEvent("apple_order_lost", new Dictionary<string, dynamic>()
{
["data"] = data.ToString(),
}, new Analytics.EventSetting()
{
EnableFirebaseAnalytics = true,
EnableFacebookAnalytics = true,
});
}
#endregion
}
}