2025-09-18 10:30:57 +00:00
#if UNITY_PURCHASE
using System.Collections ;
using System.Collections.Generic ;
using System.Linq ;
using JetBrains.Annotations ;
2025-09-18 13:49:57 +00:00
using UnityEditor ;
2025-09-18 10:30:57 +00:00
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次还是失败就不处理了
2025-09-18 13:49:57 +00:00
if ( IAPPurchaseManager . Instance . _repeatCountDic . ContainsKey ( args . info [ "order_id" ] ) )
2025-09-18 10:30:57 +00:00
{
2025-09-18 13:49:57 +00:00
IAPPurchaseManager . Instance . _repeatCountDic [ args . info [ "order_id" ] ] = IAPPurchaseManager . Instance . _repeatCountDic [ args . info [ "order_id" ] ] + 1 ;
2025-09-18 10:30:57 +00:00
}
else
{
2025-09-18 13:49:57 +00:00
IAPPurchaseManager . Instance . _repeatCountDic . Add ( args . info [ "order_id" ] , 1 ) ;
2025-09-18 10:30:57 +00:00
}
// 开始处理,设置正在处理的状态
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 )
{
// 将订阅商品信息存储到本地
2025-09-18 13:49:57 +00:00
if ( ! IAPSubscribeManager . Instance . _productArgs . ContainsKey ( args . info [ "product_id" ] . ToString ( ) ) & & args . info [ "product_type" ] . ToString ( ) . Equals ( "Subscription" ) )
2025-09-18 10:30:57 +00:00
{
2025-09-18 13:49:57 +00:00
IAPSubscribeManager . Instance . _productArgs . Add ( args . info [ "product_id" ] . ToString ( ) , requestArgs ) ;
2025-09-18 10:30:57 +00:00
}
2025-09-18 13:49:57 +00:00
else if ( IAPSubscribeManager . Instance . _productArgs . ContainsKey ( args . info [ "product_id" ] . ToString ( ) ) & & args . info [ "product_type" ] . ToString ( ) . Equals ( "Subscription" ) )
2025-09-18 10:30:57 +00:00
{
2025-09-18 13:49:57 +00:00
IAPSubscribeManager . Instance . _productArgs [ args . info [ "product_id" ] . ToString ( ) ] = requestArgs ;
2025-09-18 10:30:57 +00:00
}
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 重 置 订 单 状 态
2025-09-18 13:49:57 +00:00
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 )
2025-09-18 10:30:57 +00:00
{
2025-09-18 13:49:57 +00:00
if ( ES3 . KeyExists ( _purchaseOrderMap ) )
2025-09-18 10:30:57 +00:00
{
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 ) ;
2025-09-18 13:49:57 +00:00
ProgressCacheOrder ( ) ;
2025-09-18 10:30:57 +00:00
LoggerUtils . Debug ( "[iap] IAP SaveVerifyFailOrderId 已经有表了,添加失败订单,订单ID: " + _productInfo . info [ "order_id" ] + " 商品类型:" + _productInfo . info [ "product_type" ] ) ;
}
else
{
if ( ! inDealFailOrder )
{
inDealFailOrder = true ;
2025-09-18 13:49:57 +00:00
InvokeRepeating ( nameof ( ProgressCacheOrder ) , 0 , 30 ) ;
2025-09-18 10:30:57 +00:00
}
}
}
else
{
List < IAPDataConfig > tem = new List < IAPDataConfig >
{
_productInfo
} ;
ES3 . Save ( _purchaseOrderMap , tem ) ;
2025-09-18 13:49:57 +00:00
ProgressCacheOrder ( ) ;
2025-09-18 10:30:57 +00:00
LoggerUtils . Debug ( "[iap] IAP SaveVerifyFailOrderId 第一次存储表 添加失败订单 订单个数:" + tem . Count ) ;
}
}
#endregion
#region 再 次 验 证 订 单
2025-09-18 13:49:57 +00:00
public void ProgressCacheOrder ( )
2025-09-18 10:30:57 +00:00
{
if ( ES3 . KeyExists ( _purchaseOrderMap ) )
{
List < IAPDataConfig > list = ES3 . Load ( _purchaseOrderMap ) as List < IAPDataConfig > ;
2025-09-18 13:49:57 +00:00
LoggerUtils . Debug ( "[iap] IAP ProgressCacheOrder 读取失败订单列表, count: " + list . Count + " IAPPurchaseManager.Instance._repeatCountDic" + IAPPurchaseManager . Instance . _repeatCountDic . Count ) ;
2025-09-18 10:30:57 +00:00
if ( list . Count > 0 )
{
// 当前进程每条订单校验5次, 如果失败则不再处理
// 重复校验时判断次数是否大于5, 大于5则不再处理
IAPDataConfig tempData = null ;
2025-09-18 13:49:57 +00:00
if ( IAPPurchaseManager . Instance . _repeatCountDic . Count > 0 )
2025-09-18 10:30:57 +00:00
{
foreach ( var data in list )
{
2025-09-18 13:49:57 +00:00
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 )
2025-09-18 10:30:57 +00:00
{
tempData = data ;
break ;
}
}
}
// 如果还有次数不超过5次的订单, 则继续校验, 否则就不再处理
if ( tempData ! = null )
{
2025-09-18 13:49:57 +00:00
LoggerUtils . Debug ( "[iap] iap start verify fail order with repeat temp dic" + tempData . info [ "order_id" ] + " count:" + IAPPurchaseManager . Instance . _repeatCountDic [ tempData . info [ "order_id" ] ] ) ;
2025-09-18 10:30:57 +00:00
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" ) ;
2025-09-18 13:49:57 +00:00
CancelInvoke ( nameof ( ProgressCacheOrder ) ) ;
2025-09-18 10:30:57 +00:00
inDealFailOrder = false ;
}
}
else
{
2025-09-18 13:49:57 +00:00
CancelInvoke ( nameof ( ProgressCacheOrder ) ) ;
2025-09-18 10:30:57 +00:00
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 )
{
2025-09-18 13:49:57 +00:00
ProgressCacheOrder ( ) ;
2025-09-18 10:30:57 +00:00
}
else
{
inDealFailOrder = false ;
2025-09-18 13:49:57 +00:00
CancelInvoke ( nameof ( ProgressCacheOrder ) ) ;
2025-09-18 10:30:57 +00:00
}
}
}
#endregion
public class IAPDataConfig
{
public Dictionary < string , string > info ;
public IAPDataStateType state ;
}
}
}
#endif