418 lines
20 KiB
C#
418 lines
20 KiB
C#
#if UNITY_PURCHASE
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using JetBrains.Annotations;
|
||
using UnityEditor;
|
||
using UnityEngine;
|
||
|
||
namespace WZ
|
||
{
|
||
|
||
public class IAPOrderManager : D_MonoSingleton<IAPOrderManager>
|
||
{
|
||
private static string _purchaseOrderMap = "PurchaseOrderMap";
|
||
private List<int> NotRetryCode = new List<int> { 0, 430, 900, 901, 902, 903, 904, 905 };
|
||
|
||
#region 订单验证
|
||
public void VerifyPurchase(IAPDataConfig args)
|
||
{
|
||
LoggerUtils.Debug("[iap] Start VerifyPurchase orderid:" + args.info["order_id"] + "status:" + args.state);
|
||
if (args.state == IAPDataStateType.def)
|
||
{
|
||
// 记录订单处理次数,处理5次还是失败就不处理了
|
||
if (IAPPurchaseManager.Instance._repeatCountDic.ContainsKey(args.info["order_id"]))
|
||
{
|
||
IAPPurchaseManager.Instance._repeatCountDic[args.info["order_id"]] = IAPPurchaseManager.Instance._repeatCountDic[args.info["order_id"]] + 1;
|
||
}
|
||
else
|
||
{
|
||
IAPPurchaseManager.Instance._repeatCountDic.Add(args.info["order_id"], 1);
|
||
}
|
||
|
||
// 开始处理,设置正在处理的状态
|
||
RefreshOrderStatue(args, IAPDataStateType.deal);
|
||
args.info.TryGetValue("mGameExtraParam", out var gameExtraParam);
|
||
|
||
if (string.IsNullOrEmpty(gameExtraParam))
|
||
{
|
||
gameExtraParam = IAPPurchaseManager.Instance._gameExtraParam;
|
||
}
|
||
|
||
LoggerUtils.Debug("[iap] IAP VerifyPurchase start");
|
||
var requestArgs = args.info.ToDictionary(kv => kv.Key, kv => (object)kv.Value);
|
||
ServerMgr.Instance.VerifyPurchase(requestArgs, (code, msg, data) =>
|
||
{
|
||
RefreshOrderStatue(args, IAPDataStateType.def);
|
||
LoggerUtils.Debug("IAP VerifyPurchase CODE:" + code + " illegal:" + data.illegal_order + " env:" + data.environment);
|
||
LoggerUtils.Debug("IAP VerifyPurchase msg:" + msg);
|
||
|
||
if ((code == 0 || code == 430) && data.illegal_order == 0)
|
||
{
|
||
// 将订阅商品信息存储到本地
|
||
if (!IAPSubscribeManager.Instance._productArgs.ContainsKey(args.info["product_id"].ToString()) && args.info["product_type"].ToString().Equals("Subscription"))
|
||
{
|
||
IAPSubscribeManager.Instance._productArgs.Add(args.info["product_id"].ToString(), requestArgs);
|
||
|
||
}
|
||
else if (IAPSubscribeManager.Instance._productArgs.ContainsKey(args.info["product_id"].ToString()) && args.info["product_type"].ToString().Equals("Subscription"))
|
||
{
|
||
IAPSubscribeManager.Instance._productArgs[args.info["product_id"].ToString()] = requestArgs;
|
||
}
|
||
RushSDKManager.Instance.OnPurchaseComplete?.Invoke(new PurchaseInfo(
|
||
productName: args.info["product_name"],
|
||
productID: args.info["product_id"],
|
||
orderID: args.info["order_id"],
|
||
currency: args.info["currency"],
|
||
price: args.info["price"],
|
||
gameExtra: gameExtraParam,
|
||
failReason: "",
|
||
orderAlreadyExists: code == 430,
|
||
purchaseResult: code == 0,
|
||
resultType: IAPResultType.PurchasingSuccess,
|
||
productType: args.info["product_type"]
|
||
));
|
||
LogVerifySuccessOrder(args, data.environment, gameExtraParam, code == 430);
|
||
}
|
||
else
|
||
{
|
||
// 不需要重试的错误码
|
||
if (!NotRetryCode.Contains(code))
|
||
{
|
||
SaveVerifyFailOrderId(args);
|
||
}
|
||
|
||
// 主动删除过期订单
|
||
if (!string.IsNullOrEmpty(data.illegal_msg) && args.info["product_type"].ToString().Equals("Subscription"))
|
||
{
|
||
if (data.illegal_msg.Contains("product expired"))
|
||
{
|
||
RemoveVerifySuccessOrder(args.info["product_id"]);
|
||
}
|
||
}
|
||
if (code == -1)
|
||
{
|
||
RushSDKManager.Instance.OnPurchaseComplete?.Invoke(new PurchaseInfo(
|
||
productName: args.info["product_name"],
|
||
productID: args.info["product_id"],
|
||
orderID: args.info["order_id"],
|
||
currency: args.info["currency"],
|
||
price: args.info["price"],
|
||
gameExtra: gameExtraParam,
|
||
failReason: "",
|
||
orderAlreadyExists: code == 430,
|
||
purchaseResult: false,
|
||
resultType: IAPResultType.NULL,
|
||
productType: args.info["product_type"]
|
||
));
|
||
}
|
||
else
|
||
{
|
||
RushSDKManager.Instance.OnPurchaseComplete?.Invoke(new PurchaseInfo(
|
||
productName: args.info["product_name"],
|
||
productID: args.info["product_id"],
|
||
orderID: args.info["order_id"],
|
||
currency: args.info["currency"],
|
||
price: args.info["price"],
|
||
gameExtra: gameExtraParam,
|
||
failReason: "",
|
||
orderAlreadyExists: code == 430,
|
||
purchaseResult: false,
|
||
resultType: code == 430 ? IAPResultType.PurchasingSuccess : IAPResultType.ServerAuthenticationFailed,
|
||
productType: args.info["product_type"]
|
||
));
|
||
}
|
||
|
||
// msg 包含 illegal_order_0 说明是正常的缓存订单上报
|
||
// 卸载重装后,一次性商品
|
||
if (msg.Contains("illegal_order_0"))
|
||
{
|
||
LogVerifySuccessOrder(args, msg.Contains("sandbox") ? "sandbox" : "production", gameExtraParam, code == 430);
|
||
}
|
||
else
|
||
{
|
||
LogVerifyFailOrder(args, gameExtraParam, $"Purchase service code : {code} msg : {msg} dataMsg:{data.illegal_msg} illegal_order:{data.illegal_order} environment:{(msg.Contains("sandbox") ? "sandbox" : "production")}");
|
||
}
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
private void LogVerifySuccessOrder(IAPDataConfig _productInfo, string _enviroment, string _gameExtraParam, bool _orderAlreadyExists)
|
||
{
|
||
IAPEvent.LogPurchaseSuccess(new PurchaseInfo(
|
||
productName: _productInfo.info["product_name"],
|
||
productID: _productInfo.info["product_id"],
|
||
orderID: _productInfo.info["order_id"],
|
||
currency: _productInfo.info["currency"],
|
||
price: _productInfo.info["price"],
|
||
gameExtra: _gameExtraParam,
|
||
failReason: "",
|
||
orderAlreadyExists: _orderAlreadyExists,
|
||
purchaseResult: !_orderAlreadyExists,
|
||
resultType: IAPResultType.NULL,
|
||
productType: _productInfo.info["product_type"]
|
||
), _enviroment);
|
||
}
|
||
|
||
private void LogVerifyFailOrder(IAPDataConfig _productInfo, string _gameExtraParam, string _errInfo)
|
||
{
|
||
|
||
IAPEvent.LogPurchaseFail(new PurchaseInfo(
|
||
productName: _productInfo.info["product_name"],
|
||
productID: _productInfo.info["product_id"],
|
||
orderID: _productInfo.info["order_id"],
|
||
currency: _productInfo.info["currency"],
|
||
price: _productInfo.info["price"],
|
||
gameExtra: _gameExtraParam,
|
||
failReason: _errInfo,
|
||
orderAlreadyExists: false,
|
||
purchaseResult: false,
|
||
resultType: IAPResultType.NULL,
|
||
productType: _productInfo.info["product_type"]
|
||
));
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 重置订单状态
|
||
public void RefreshOrderStatue()
|
||
{
|
||
if (ES3.KeyExists(_purchaseOrderMap))
|
||
{
|
||
try
|
||
{
|
||
List<IAPDataConfig> list = ES3.Load("FailOrderCacheData") as List<IAPDataConfig>;
|
||
if (list.Count > 0)
|
||
{
|
||
foreach (var data in list)
|
||
{
|
||
data.state = IAPDataStateType.def;
|
||
}
|
||
ES3.Save("FailOrderCacheData", list);
|
||
}
|
||
}
|
||
catch (System.Exception)
|
||
{
|
||
ES3.DeleteKey("FailOrderCacheData");
|
||
}
|
||
}
|
||
}
|
||
public void RefreshOrderStatue(IAPDataConfig _productInfo, IAPDataStateType state)
|
||
{
|
||
if (ES3.KeyExists(_purchaseOrderMap))
|
||
{
|
||
List<IAPDataConfig> list = ES3.Load(_purchaseOrderMap) as List<IAPDataConfig>;
|
||
var value = _productInfo.info["order_id"];
|
||
var want = list.Find(e => e.info.ContainsValue(value));
|
||
if (want != null)
|
||
{
|
||
want.state = state;
|
||
ES3.Save(_purchaseOrderMap, list);
|
||
}
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 存储订单
|
||
public void SaveOrder(IAPDataConfig _productInfo)
|
||
{
|
||
if (ES3.KeyExists(_purchaseOrderMap))
|
||
{
|
||
List<IAPDataConfig> list = ES3.Load(_purchaseOrderMap) as List<IAPDataConfig>;
|
||
var want = list.Find(e => e.info.ContainsValue(_productInfo.info["order_id"]));
|
||
if (want == null)
|
||
{
|
||
list.Add(_productInfo);
|
||
ES3.Save(_purchaseOrderMap, list);
|
||
IAPEvent.LogSaveOrderBySdk(new PurchaseInfo(
|
||
productName: _productInfo.info["product_name"],
|
||
productID: _productInfo.info["product_id"],
|
||
orderID: _productInfo.info["order_id"],
|
||
currency: _productInfo.info["currency"],
|
||
price: _productInfo.info["price"],
|
||
gameExtra: _productInfo.info["mGameExtraParam"],
|
||
productType: _productInfo.info["product_type"],
|
||
failReason: null,
|
||
orderAlreadyExists: false,
|
||
purchaseResult: false,
|
||
resultType: IAPResultType.NULL
|
||
));
|
||
|
||
LoggerUtils.Debug("[iap] IAP SaveOrder 已经有表了,添加订单,订单ID:" + _productInfo.info["order_id"] + " 未验证订单个数:" + list.Count);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
List<IAPDataConfig> tem = new List<IAPDataConfig>
|
||
{
|
||
_productInfo
|
||
};
|
||
ES3.Save(_purchaseOrderMap, tem);
|
||
IAPEvent.LogSaveOrderBySdk(new PurchaseInfo(
|
||
productName: _productInfo.info["product_name"],
|
||
productID: _productInfo.info["product_id"],
|
||
orderID: _productInfo.info["order_id"],
|
||
currency: _productInfo.info["currency"],
|
||
price: _productInfo.info["price"],
|
||
gameExtra: _productInfo.info["mGameExtraParam"],
|
||
productType: _productInfo.info["product_type"],
|
||
failReason: null,
|
||
orderAlreadyExists: false,
|
||
purchaseResult: false,
|
||
resultType: IAPResultType.NULL
|
||
));
|
||
LoggerUtils.Debug("[iap] IAP SaveOrder 第一次存储表 添加订单ID:" + _productInfo.info["order_id"] + " 商品类型:" + _productInfo.info["product_type"] + " 订单个数:" + tem.Count);
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 保存验证失败订单
|
||
private bool inDealFailOrder;
|
||
private void SaveVerifyFailOrderId(IAPDataConfig _productInfo)
|
||
{
|
||
LoggerUtils.Debug("[iap] iap save verify fail order,orderId:" + _productInfo.info["order_id"] + " 商品类型:" + _productInfo.info["product_type"]);
|
||
if (ES3.KeyExists(_purchaseOrderMap))
|
||
{
|
||
List<IAPDataConfig> list = ES3.Load(_purchaseOrderMap) as List<IAPDataConfig>;
|
||
|
||
var value = _productInfo.info["order_id"];
|
||
var want = list.Find(e => e.info.ContainsValue(value));
|
||
if (want == null)
|
||
{
|
||
list.Add(_productInfo);
|
||
ES3.Save(_purchaseOrderMap, list);
|
||
ProgressCacheOrder();
|
||
LoggerUtils.Debug("[iap] IAP SaveVerifyFailOrderId 已经有表了,添加失败订单,订单ID:" + _productInfo.info["order_id"] + " 商品类型:" + _productInfo.info["product_type"]);
|
||
}
|
||
else
|
||
{
|
||
if (!inDealFailOrder)
|
||
{
|
||
inDealFailOrder = true;
|
||
InvokeRepeating(nameof(ProgressCacheOrder), 0, 30);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
List<IAPDataConfig> tem = new List<IAPDataConfig>
|
||
{
|
||
_productInfo
|
||
};
|
||
ES3.Save(_purchaseOrderMap, tem);
|
||
ProgressCacheOrder();
|
||
LoggerUtils.Debug("[iap] IAP SaveVerifyFailOrderId 第一次存储表 添加失败订单 订单个数:" + tem.Count);
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 再次验证订单
|
||
public void ProgressCacheOrder()
|
||
{
|
||
if (ES3.KeyExists(_purchaseOrderMap))
|
||
{
|
||
List<IAPDataConfig> list = ES3.Load(_purchaseOrderMap) as List<IAPDataConfig>;
|
||
LoggerUtils.Debug("[iap] IAP ProgressCacheOrder 读取失败订单列表,count:" + list.Count + " IAPPurchaseManager.Instance._repeatCountDic" + IAPPurchaseManager.Instance._repeatCountDic.Count);
|
||
if (list.Count > 0)
|
||
{
|
||
// 当前进程每条订单校验5次,如果失败则不再处理
|
||
// 重复校验时判断次数是否大于5,大于5则不再处理
|
||
IAPDataConfig tempData = null;
|
||
if (IAPPurchaseManager.Instance._repeatCountDic.Count > 0)
|
||
{
|
||
foreach (var data in list)
|
||
{
|
||
LoggerUtils.Debug("[iap] iap start verify fail order with repeat dic" + data.info["order_id"] + " count:" + IAPPurchaseManager.Instance._repeatCountDic[data.info["order_id"]]);
|
||
if (IAPPurchaseManager.Instance._repeatCountDic.ContainsKey(data.info["order_id"]) && IAPPurchaseManager.Instance._repeatCountDic[data.info["order_id"]] <= 5)
|
||
{
|
||
tempData = data;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
// 如果还有次数不超过5次的订单,则继续校验,否则就不再处理
|
||
if (tempData != null)
|
||
{
|
||
LoggerUtils.Debug("[iap] iap start verify fail order with repeat temp dic" + tempData.info["order_id"] + " count:" + IAPPurchaseManager.Instance._repeatCountDic[tempData.info["order_id"]]);
|
||
VerifyPurchase(tempData);
|
||
IAPEvent.LogStarVerifyOrderBySdk(new PurchaseInfo(
|
||
productName: tempData.info["product_name"],
|
||
productID: tempData.info["product_id"],
|
||
orderID: tempData.info["order_id"],
|
||
currency: tempData.info["currency"],
|
||
price: tempData.info["price"],
|
||
gameExtra: tempData.info["mGameExtraParam"],
|
||
productType: tempData.info["product_type"],
|
||
failReason: null,
|
||
orderAlreadyExists: false,
|
||
purchaseResult: false,
|
||
resultType: IAPResultType.NULL));
|
||
}
|
||
else
|
||
{
|
||
LoggerUtils.Debug("[iap] iap cancel verify fail order");
|
||
CancelInvoke(nameof(ProgressCacheOrder));
|
||
inDealFailOrder = false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
CancelInvoke(nameof(ProgressCacheOrder));
|
||
inDealFailOrder = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 移除订单
|
||
// 校验成功后移除订单
|
||
public void RemoveVerifySuccessOrder(string orderId)
|
||
{
|
||
if (ES3.KeyExists(_purchaseOrderMap))
|
||
{
|
||
List<IAPDataConfig> list = ES3.Load(_purchaseOrderMap) as List<IAPDataConfig>;
|
||
var want = list.Find(e => e.info.ContainsValue(orderId));
|
||
if (want != null)
|
||
{
|
||
LoggerUtils.Debug("[iap] IAP RemoveVerifySuccessOrder 找到并移除订单,订单ID:" + orderId);
|
||
list.Remove(want);
|
||
IAPEvent.LogRemoveOrderBySdk(new PurchaseInfo(
|
||
productName: want.info["product_name"],
|
||
productID: want.info["product_id"],
|
||
orderID: want.info["order_id"],
|
||
currency: want.info["currency"],
|
||
price: want.info["price"],
|
||
gameExtra: want.info["mGameExtraParam"],
|
||
productType: want.info["product_type"],
|
||
failReason: null,
|
||
orderAlreadyExists: false,
|
||
purchaseResult: false,
|
||
resultType: IAPResultType.NULL));
|
||
ES3.Save(_purchaseOrderMap, list);
|
||
}
|
||
|
||
LoggerUtils.Debug("[iap] IAP 订单还剩余:" + list.Count + " 条未校验");
|
||
if (list.Count > 0)
|
||
{
|
||
ProgressCacheOrder();
|
||
}
|
||
else
|
||
{
|
||
inDealFailOrder = false;
|
||
CancelInvoke(nameof(ProgressCacheOrder));
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
public class IAPDataConfig
|
||
{
|
||
public Dictionary<string, string> info;
|
||
public IAPDataStateType state;
|
||
}
|
||
}
|
||
}
|
||
#endif
|