feat:1、添加项目

This commit is contained in:
2026-06-02 10:26:44 +08:00
commit dfead2c461
7518 changed files with 748693 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: af9d868830da4e39ac9dacbd87918ec1
timeCreated: 1756198041
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 752ae72dcb564aed925a1e54f34c9751
timeCreated: 1756198065
@@ -0,0 +1,59 @@
using Newtonsoft.Json;
namespace SGModule.GooglePay
{
public class GooglePayData
{
[JsonProperty("innerOrderId")] public string innerOrderId;
[JsonProperty("amount")] public int amount;
[JsonProperty("sku")] public string sku;
[JsonProperty("currency")] public string currency = "USD";
[JsonProperty("shopName")] public string shopName;
[JsonProperty("type")] public string type;
[JsonProperty("status")] public int status;
[JsonProperty("orderId")] public string orderId;
[JsonProperty("packageName")] public string packageName;
[JsonProperty("productId")] public string productId;
[JsonProperty("purchaseToken")] public string purchaseToken;
[JsonProperty("purchaseState")] public int purchaseState;
[JsonProperty("test")] public bool test;
[JsonProperty("isCompleted")] public bool isCompleted;
}
public class GoogleCheckData
{
[JsonProperty("signedPayload")] public string signedPayload;
[JsonProperty("innerOrderId")] public string innerOrderId;
}
public class GooglePayCancelInfo
{
[JsonProperty("innerOrderId")] public string innerOrderId;
[JsonProperty("reason")] public string reason;
[JsonProperty("message")] public string message;
[JsonProperty("productId")] public string productId;
}
public class GoogleSubscribeData
{
[JsonProperty("orderId")] public string orderId;
[JsonProperty("packageName")] public string packageName;
[JsonProperty("productId")] public string productId;
[JsonProperty("purchaseState")] public int purchaseState;
[JsonProperty("purchaseToken")] public string purchaseToken;
[JsonProperty("sku")] public string sku;
[JsonProperty("amount")] public int amount;
[JsonProperty("currency")] public string currency = "USD";
[JsonProperty("expires_time")] public long expires_time;
}
public class GoogleSubscribeDataHistory
{
[JsonProperty("orig_tx_id")] public string orig_tx_id;
[JsonProperty("sku")] public string sku;
[JsonProperty("status")] public int status;
[JsonProperty("renew_time")] public long renew_time;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: be118fdd590a4ce7825e12a2d432f7a4
timeCreated: 1756198178
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: eea901421b8f43738bb0222236ed670b
timeCreated: 1756198077
@@ -0,0 +1,22 @@
namespace SGModule.GooglePay
{
public enum GooglePayBackType
{
/// <summary>
///创建支付订单
/// </summary>
Create,
/// <summary>
///验证支付订单
/// </summary>
Check,
/// <summary>
///取消支付订单
/// </summary>
Cancel,
/// <summary>
///支付超时(可能多个订单,或者未联网时,拉起支付时支付数据需要1分钟后重置,需要进行提示处理)
/// </summary>
TimeOut,
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 15fef0f3bf56425e85298d8e4c41921f
timeCreated: 1756199124
@@ -0,0 +1,957 @@
using SGModule.Common.Base;
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using SGModule.Common.Helper;
using SGModule.DataStorage;
using SGModule.NetKit;
#if UNITY_IAP
using System.Collections;
using System.Linq;
using DG.Tweening;
using SGModule.Common.Extensions;
using Newtonsoft.Json;
using SGModule.Net;
using UnityEngine;
using UnityEngine.Purchasing;
using UnityEngine.Purchasing.Extension;
namespace SGModule.GooglePay
{
public class GooglePayManager : SingletonMonoBehaviour<GooglePayManager>, IDetailedStoreListener
{
private static readonly string SubscriptionExpiresTime = "SubscriptionExpiresTime";
private IStoreController _storeController;
private static IExtensionProvider _extensionProvider;
private static IGooglePlayStoreExtensions _googleExtension;
private static IAppleExtensions _appleExtension;
private Action<string> _failedCallback;
private Action<GooglePayBackType, GoogleResponseData> _successCallback;
private Dictionary<string, (string id, string type)> _products = new();
private GooglePayData _payData;
private string _packageName;
private float _lastPayAttemptTime;
public void SendDebugToServer(string error, string stackTrace = "")
{
// ErrorLogKit.Send("debug", error, stackTrace);
}
private Dictionary<string, PayProductConfig> _productConfigs = new();
private Dictionary<string, string> _innerData = new();
/// <summary>
/// 通过 ProductConfig 数组初始化商品
/// </summary>
public void InitProduct(List<PayProductConfig> configs, string packageName,
Action<GooglePayBackType, GoogleResponseData> successCallback)
{
var module = StandardPurchasingModule.Instance();
ConfigurationBuilder builder = ConfigurationBuilder.Instance(module);
_successCallback = successCallback;
_packageName = packageName;
SendDebugToServer("[Google pay] InitProduct 开始------");
try
{
foreach (var config in configs)
{
Debug.Log($"[Google pay] InitProduct ------{config.sku} , {config.type} ");
if (Enum.TryParse<ProductType>(config.type, true, out var productType))
{
_productConfigs.Add(config.sku, config);
builder.AddProduct(config.sku, productType);
}
else
{
SendDebugToServer($"无法解析 ProductType: {config.type}");
Debug.LogError($"无法解析 ProductType: {config.type}");
// 可根据需要处理默认类型或跳过该商品
}
}
SendDebugToServer("[Google pay] InitProduct 结束------");
UnityPurchasing.Initialize(this, builder);
}
catch (Exception e)
{
SendDebugToServer($" 初始化" +
$"商品 失败 InitProduct: {e.Message}");
Console.WriteLine(e);
throw;
}
Debug.Log($"[Google pay] InitProduct -----2 ");
}
private void SetPayData(string sku)
{
var payData = GetPayData(sku);
_payData = payData;
}
private GooglePayData GetPayData(string sku)
{
if (_productConfigs.TryGetValue(sku, out var data))
{
Debug.Log($"[Google pay] InitProduct ------{data.sku} , {data.type} ");
return new GooglePayData
{
sku = sku,
currency = "USD",
amount = (int)Math.Round(data.price * 100),
};
}
Debug.LogError($" set _payData error------_payData is null ");
return null;
}
private Coroutine _payDataCheckCoroutine;
/// <summary>
/// 启动_payData超时检测协程
/// </summary>
private void StartPayDataTimeoutCheck()
{
if (_payDataCheckCoroutine != null)
{
StopCoroutine(_payDataCheckCoroutine);
}
_payDataCheckCoroutine = StartCoroutine(PayDataTimeoutCheck());
}
/// <summary>
/// 检测_payData是否超时的协程
/// </summary>
private IEnumerator PayDataTimeoutCheck()
{
float startTime = Time.time;
float timeout = 30f; // 1分钟超时
if (_payData.innerOrderId == null)
{
timeout = 10f;
}
while (Time.time - startTime < timeout)
{
// 如果_payData已经为null,停止检测
if (_payData == null)
{
yield break;
}
yield return null;
}
// 1分钟后检查,如果_payData仍然不为null,则设为null
if (_payData != null)
{
_innerData = null;
_payData = null;
Debug.Log("[Apple Pay] _payData超时,已自动设为null");
}
}
/// <summary>
/// 购买接口
/// </summary>
/// <param name="payData">购买需要的字段存放</param>
/// <param name="successCallback">成功回调(ApplePayBackType为订单返回的类型:具体看 ApplePayBackType 枚举),作用:用来打点</param>
/// <param name="failedCallback">失败回调 string为失败原因)</param>
public void Purchase(string sku, Action<GooglePayBackType, GoogleResponseData> successCallback,
Action<string> failedCallback)
{
Debug.Log($"[Google pay] Purchase-0--------- {JsonConvert.SerializeObject(_payData)}");
SendDebugToServer("[Google pay] 购买 Purchase ------");
if (Time.time - _lastPayAttemptTime < 5)
{
failedCallback?.Invoke("Clicks are too frequent");
return;
}
_lastPayAttemptTime = Time.time;
Debug.Log($"[Google pay] Purchase-1---------{JsonConvert.SerializeObject(_payData)}");
if (_payData != null)
{
//启动_payData超时检测协程
StartPayDataTimeoutCheck();
_successCallback?.Invoke(GooglePayBackType.TimeOut, null);
return;
}
Debug.Log($"[Google pay] Purchase-2---------");
if (!IsInitialized())
{
failedCallback?.Invoke("Not Initialized");
return;
}
Debug.Log($"[Google pay] Purchase-3---------{sku}");
var product = _storeController.products.WithID(sku);
if (product == null)
{
failedCallback?.Invoke("product is not found ");
return;
}
if (!product.availableToPurchase)
{
failedCallback?.Invoke("product is not available for purchase");
return;
}
_successCallback = successCallback;
_failedCallback = failedCallback;
SetPayData(sku);
Debug.Log($"[Google pay] Purchase-4---------");
if (_payData != null)
{
var payData = new GooglePayData
{
sku = sku,
currency = "USD",
amount = _payData.amount,
};
if (_productConfigs.TryGetValue(sku, out var data))
{
if (Enum.TryParse<ProductType>(data.type, true, out var productType))
{
Debug.Log($"[google pay] 是否是订阅类型=== {productType}");
if (productType == ProductType.Subscription)
{
_successCallback(GooglePayBackType.Create, null);
_storeController.InitiatePurchase(product);
return;
}
}
}
GooglePayNet.GooglePayCreate<GooglePayData>(payData, (response) =>
{
Debug.Log($"[Google pay] Purchase-5---------{response.IsSuccess}");
if (response.IsSuccess)
{
if (_innerData == null) _innerData = new();
_successCallback?.Invoke(GooglePayBackType.Create, null);
Debug.Log($"[Google pay] Purchase--5-innerOrderId-------{response.Data.innerOrderId}");
if (_payData != null && response.Data.innerOrderId != null)
{
Debug.Log($"[Google pay] Purchase-555555-innerOrderId");
_payData.innerOrderId = response.Data.innerOrderId;
_innerData[response.Data.innerOrderId] = sku;
SaveInnerIdData(_innerData);
}
_storeController.InitiatePurchase(product);
}
SendDebugToServer($"[Google pay] Purchase-6-------创建内部ID innerOrderId--{_payData.innerOrderId}");
Debug.Log($"[Google pay] Purchase-7-------innerOrderId--{_payData.innerOrderId}");
});
}
}
/// <summary>
/// IOS恢复内购
/// 会在删除应用后,第一次安装是自动恢复
/// </summary>
/// <param name="restoreCallback">恢复回调</param>
public void AppleRestore(Action<bool, string> restoreCallback)
{
if (!IsInitialized())
{
Debug.LogWarning("[IAP] IAppleExtensions 未初始化");
return;
}
Debug.Log("[IAP] 用户手动恢复购买");
_appleExtension.RestoreTransactions((success, error) =>
{
if (success)
{
Debug.Log("[Google pay] Restore Transactions 成功");
// 这里会触发 ProcessPurchase 回调
restoreCallback(true, error);
}
else
{
Debug.LogError($"[Google pay] Restore Transactions 失败: {error}");
// 可以提示用户重试
}
});
}
#region
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent)
{
var product = purchaseEvent.purchasedProduct;
var productType = product.definition.type;
var sku = product.definition.id;
Debug.Log($" ProcessPurchase 1 Purchase: {JsonConvert.SerializeObject(purchaseEvent.purchasedProduct)}");
if (purchaseEvent is not { purchasedProduct: not null })
{
Debug.LogError("[Google pay] ProcessPurchase 2 : purchaseEvent 或 purchasedProduct 为 null");
return PurchaseProcessingResult.Complete;
}
Debug.Log($"购买商品类型: {productType}, SKU: {sku}");
if (productType == ProductType.Subscription)
{
SendDebugToServer($"[Google pay] 购买商品类型 Purchase ---{productType}-{sku}--");
// 服务器验证
UploadReceiptForValidation(purchaseEvent, sku, isSuccess =>
{
// if (isSuccess)
// {
// // 验证成功后的逻辑
// // 验证成功,完成购买
// _storeController.ConfirmPendingPurchase(product);
// }
_storeController.ConfirmPendingPurchase(product);
});
return PurchaseProcessingResult.Pending;
}
if (productType == ProductType.NonConsumable)
{
Debug.Log($" 识别到非消耗性商品 ----{DataMgr.ApplePayTransactionID.Value.Contains(product.transactionID)}");
if (DataMgr.ApplePayTransactionID.Value.Contains(product.transactionID))
{
return PurchaseProcessingResult.Complete;
}
DataMgr.ApplePayTransactionID.Value.Add(product.transactionID);
}
// 普通商品直接处理
HandlePurchaseSuccess(purchaseEvent, isSuccess =>
{
Debug.Log($"普通商品直接处理 isSuccess==========={isSuccess}");
// if (isSuccess)
// {
// // 验证成功,完成购买
// _storeController.ConfirmPendingPurchase(product);
// }
_storeController.ConfirmPendingPurchase(product);
});
return PurchaseProcessingResult.Pending;
}
//服务器验证
private void UploadReceiptForValidation(PurchaseEventArgs purchaseEvent, string sku,
Action<bool> onValidationComplete)
{
Debug.Log("识别到订阅商品,准备进行订阅验证");
SendDebugToServer($"[Google pay] 识别到订阅商品,准备进行订阅验证");
var productConfig = GetPayData(sku);
if (productConfig != null)
{
var receiptObj = JObject.Parse(purchaseEvent.purchasedProduct.receipt);
var payload = JObject.Parse((string)receiptObj["Payload"]);
var jsonData = JObject.Parse((string)payload["json"]);
var transactionID = purchaseEvent.purchasedProduct.transactionID;
Debug.Log($"订阅商品ID: {sku} transactionID: {transactionID} _payData.amount: {productConfig.amount}");
SendDebugToServer(
$"订阅商品ID: {sku} transactionID: {transactionID} _payData.amount: {productConfig.amount}");
GoogleSubscribeData requestData = new()
{
orderId = (string)jsonData["orderId"],
packageName = _packageName,
productId = (string)jsonData["productId"],
purchaseState = (int)jsonData["purchaseState"],
purchaseToken = (string)jsonData["purchaseToken"],
sku = sku,
amount = GetPayData(sku).amount,
currency = "USD"
};
GooglePayNet.GoogleSubscribeCheck<GoogleSubscribeData>(
requestData,
response =>
{
bool isSuccess = response.IsSuccess;
// 在这里返回验证结果
onValidationComplete?.Invoke(isSuccess);
_payData = null;
if (isSuccess)
{
Debug.Log("订阅验证成功");
SendDebugToServer($"订阅验证成功");
SaveSubscriptionExpireTime(response.Data.expires_time);
_successCallback?.Invoke(GooglePayBackType.Check, new GoogleResponseData()
{
expires_time = response.Data.expires_time,
sku = sku
});
}
else
{
Debug.LogWarning("[Google pay] 订阅验证失败");
}
});
}
}
/// <summary>
/// 支付成功后的本地处理(订阅和普通商品共用)
/// </summary>
private void HandlePurchaseSuccess(PurchaseEventArgs purchaseEvent, Action<bool> onValidationComplete,
bool isTest = false)
{
var payDataJson = GetApplePayData();
Debug.Log($" HandlePurchaseSuccess payDataJson: {JsonConvert.SerializeObject(payDataJson)}");
var statusDictionary = JsonConvert.DeserializeObject<Dictionary<string, GooglePayData>>(payDataJson)
?? new Dictionary<string, GooglePayData>();
string transactionID = purchaseEvent.purchasedProduct.transactionID;
SendDebugToServer($"普通商品 HandlePurchaseSuccess: {transactionID}");
Debug.Log($"[google pay] 购买成功: transactionID: {transactionID}");
var receiptObj = JObject.Parse(purchaseEvent.purchasedProduct.receipt);
var payload = JObject.Parse((string)receiptObj["Payload"]);
var jsonData = JObject.Parse((string)payload["json"]);
Debug.Log($"[google pay] 购买成功: orderId: {(string)jsonData["orderId"]}");
//GPA.3320-7000-4171-67632
//efbjipchlddmgamgdjkmidcn.AO-J1Oy9pfnlyIpj7qvbisgYb55XEGtV-GDr1Q-HoR96N1jZp3YRvgJRTajlxFaws3CxF-Qu6mXY2WHIPqjO7Ul3eSNHOC5PaD9LaF4Mv0ZNq7e5IcIaMSs
if (!statusDictionary.ContainsKey(transactionID))
{
Debug.Log($"记录新交易 transactionID: {transactionID}");
Debug.Log($"-----_payData: {JsonConvert.SerializeObject(_payData)}");
if (_payData == null || string.IsNullOrWhiteSpace(_payData.innerOrderId))
{
Debug.Log("[Google pay] _payData 为空或 innerOrderId 无效");
var innerdata = GetInnerIdData();
var isFind = false;
Debug.Log($" HandlePurchaseSuccess innerdata: {JsonConvert.SerializeObject(innerdata)}");
if (innerdata != null)
{
foreach (var item in innerdata)
{
Debug.Log(
$" HandlePurchaseSuccess item: {item.Key} {item.Value} jsonData productId=={(string)jsonData["productId"]}");
if (item.Value == (string)jsonData["productId"])
{
_payData = new()
{
innerOrderId = item.Key
};
isFind = true;
break;
}
}
}
if (!isFind)
{
Debug.LogWarning("[Google pay] 内部订单ID 无效");
onValidationComplete?.Invoke(false);
return;
}
}
_payData.orderId = (string)jsonData["orderId"];
_payData.packageName = (string)jsonData["packageName"];
_payData.productId = (string)jsonData["productId"];
_payData.purchaseToken = (string)jsonData["purchaseToken"];
_payData.purchaseState = (int)jsonData["purchaseState"];
statusDictionary.Add(transactionID, _payData);
SaveApplePayData(statusDictionary);
_innerData = null;
_payData = null;
}
if (statusDictionary.TryGetValue(transactionID, out var cValue))
{
if (!string.IsNullOrWhiteSpace(cValue.innerOrderId) || isTest)
{
ApplePaySuccess(transactionID, onValidationComplete);
}
}
}
#region
private int _retryCount = 0;
private const int MaxRetryCount = 2;
private const float RetryDelay = 60f;
public void CheckSubscription(Action<bool> onFinish)
{
GooglePayNet.GoogleSubscribeHistory<List<GoogleSubscribeDataHistory>>(null, (response) =>
{
if (response.IsSuccess)
{
var responseData = response.Data;
Debug.Log($"[Google pay] 订阅检查成功: {JsonConvert.SerializeObject(responseData)}");
if (responseData == null || responseData.Count == 0)
{
// Debug.Log($"[Google pay] 订阅检查成功: {JsonConvert.SerializeObject(responseData)}");
return;
}
GoogleSubscribeDataHistory latestSubscription = null;
foreach (var sub in responseData)
{
if (latestSubscription == null || sub.renew_time > latestSubscription.renew_time)
{
latestSubscription = sub;
}
}
//服务器时间
long currentTime = ServerClock.GetCurrentServerTime();
Debug.Log($"[Google pay] latestSubscription: {JsonConvert.SerializeObject(latestSubscription)}");
Debug.Log($"[Google pay] 订阅检查失效时间: currentTime: {currentTime} renew_time: {latestSubscription.renew_time}");
if (currentTime < latestSubscription.renew_time)
{
Debug.Log($"[Google pay] 订阅检查成功:");
_successCallback(GooglePayBackType.Check, new GoogleResponseData()
{
sku = latestSubscription.sku,
expires_time = latestSubscription.renew_time
});
_retryCount = 0;
onFinish?.Invoke(true); // ✅ 成功 → 解锁
}
else
{
Retry(onFinish);
}
}
else
{
Retry(onFinish);
}
});
}
private void Retry(Action<bool> onFinish)
{
if (_retryCount < MaxRetryCount)
{
_retryCount++;
Debug.Log($"[Google pay] latestSubscription == null{RetryDelay} 秒后重试,第 {_retryCount} 次...");
StartCoroutine(RetryCoroutine(onFinish));
}
else
{
Debug.LogError("[Google pay] 订阅检查失败,已达到最大重试次数!");
_retryCount = 0;
onFinish?.Invoke(false); // ✅ 失败 → 解锁
}
}
private IEnumerator RetryCoroutine(Action<bool> onFinish)
{
yield return new WaitForSeconds(RetryDelay);
CheckSubscription(onFinish);
}
#endregion
public static DataStorage<long> VipExpirationTime = new(SubscriptionExpiresTime);
/// <summary>
/// 保存订阅失效时间
/// </summary>
/// <param name="expires_time">过期时间戳</param>
private void SaveSubscriptionExpireTime(long expires_time)
{
var expireTime = expires_time;
if (expireTime > 0)
{
VipExpirationTime.Value = expireTime;
Debug.Log($"[Google pay] 保存订阅失效时间: {expireTime}");
VipExpirationTime.Save();
}
}
private void SaveApplePayData(Dictionary<string, GooglePayData> payData)
{
// 保存更新后的数据
string json = JsonConvert.SerializeObject(payData);
PlayerPrefs.SetString("SGModule_apple_pay_data", json);
}
private string GetApplePayData()
{
string json = PlayerPrefs.GetString("SGModule_apple_pay_data", "");
// GetString if (json == "")
// {
// json = DataWrapper.ApplePayData;
// }
return json;
}
private void SaveInnerIdData(Dictionary<string, string> innerData)
{
// 保存更新后的数据
string json = JsonConvert.SerializeObject(innerData);
Debug.Log($"[Inner save Data] ==: {json}");
PlayerPrefs.SetString("SGModule_inner_order_id", json);
}
private Dictionary<string, string> GetInnerIdData()
{
string json = PlayerPrefs.GetString("SGModule_inner_order_id", "");
Debug.Log($"[Inner get Data] ==: {json}");
return JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
}
private void ApplePaySuccess(string transactionID, Action<bool> onValidationComplete)
{
Debug.Log("apple 支付 StartCoroutine------");
StartCoroutine(ProcessPayData(transactionID, onValidationComplete));
}
private IEnumerator ProcessPayData(string orderId, Action<bool> onValidationComplete)
{
// 发起请求
ApplePayRequest(orderId, onValidationComplete);
yield return null; // 等待本次请求完成
}
private void ApplePayRequest(string transactionID, Action<bool> onValidationComplete)
{
var payDataJson = GetApplePayData();
Debug.Log($"[IAP] ApplePayRequest 1 payDataJson: {JsonConvert.SerializeObject(payDataJson)}");
SendDebugToServer($"验单 普通商品: {transactionID}");
var statusDictionary = JsonConvert.DeserializeObject<Dictionary<string, GooglePayData>>(payDataJson);
if (statusDictionary.ContainsKey(transactionID))
{
Debug.Log($"[IAP] ApplePayRequest 2 transactionID: {transactionID}");
var data = statusDictionary[transactionID];
GooglePayCheckInfo reqData = new()
{
innerOrderId = data.innerOrderId,
orderId = data.orderId,
packageName = data.packageName,
productId = data.productId,
purchaseToken = data.purchaseToken,
purchaseState = data.purchaseState,
test = false,
};
GooglePayNet.GooglePayCheck<GooglePayData>(reqData, _packageName, (response) =>
{
Debug.Log(
$"[IAP] ApplePayRequest 3 response.IsSuccess: {JsonConvert.SerializeObject(response)}");
onValidationComplete?.Invoke(response.IsSuccess);
if (response.IsSuccess)
{
_successCallback(GooglePayBackType.Check, new GoogleResponseData()
{
sku = data.productId
});
var innerdata = GetInnerIdData();
innerdata.Remove(data.innerOrderId);
SaveInnerIdData(innerdata);
statusDictionary.Remove(transactionID);
// 保存更新后的数据
SaveApplePayData(statusDictionary);
_innerData = null;
_payData = null;
}
if (!new List<int>() { 1021, 1026, 1027, 1028 }.Contains(response.Code))
{
}
else
{
statusDictionary.Remove(transactionID);
// 保存更新后的数据
SaveApplePayData(statusDictionary);
var innerdata = GetInnerIdData();
innerdata.Remove(reqData.innerOrderId);
SaveInnerIdData(innerdata);
}
});
}
}
#endregion
#region
private bool IsInitialized()
{
Debug.Log("[IAP] check IsInitialized======:");
return _storeController != null && _extensionProvider != null;
}
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
Debug.Log("[IAP] OnInitialized success======:");
SendDebugToServer($" OnInitialized 初始化成功 :");
_storeController = controller;
_extensionProvider = extensions;
_appleExtension = extensions.GetExtension<IAppleExtensions>();
_googleExtension = extensions.GetExtension<IGooglePlayStoreExtensions>();
}
public void OnInitializeFailed(InitializationFailureReason error)
{
Debug.Log("[IAP] OnInitializeFailed1 Reason:" + error);
SendDebugToServer($" OnInitializeFailed 初始化失败 :");
// throw new NotImplementedException();
}
public void OnInitializeFailed(InitializationFailureReason error, string message)
{
Debug.Log("[IAP] OnInitializeFailed2 Reason:" + error);
Debug.Log("[IAP] OnInitializeFailed2 message:" + message);
SendDebugToServer($" OnInitializeFailed 初始化失败 {message}");
// throw new NotImplementedException();
}
#endregion
#region
public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
{
Debug.Log("[google fail] OnPurchaseFailed===1==:");
HandleOnPurchaseFail(product, failureReason);
}
public void OnPurchaseFailed(Product product, PurchaseFailureDescription failureDescription)
{
Debug.Log("[google fail] OnPurchaseFailed===2==:");
if (failureDescription != null)
{
HandleOnPurchaseFail(product, failureDescription.reason, failureDescription);
}
// if (failureDescription.reason.ToString() == "DuplicateTransaction")
// {
// Debug.Log("DuplicateTransaction detected, restoring transactions...");
//
// var googlePlay = _extensionProvider.GetExtension<IGooglePlayStoreExtensions>();
// googlePlay.RestoreTransactions((success, msg) =>
// {
// Debug.Log($"RestoreTransactions result: {success}, message: {msg}");
// // 发奖励逻辑不要写这里,ProcessPurchase 会处理未完成订单
//
// if (success)
// {
// _storeController.ConfirmPendingPurchase(product);
// }
// });
// }
}
private void HandleOnPurchaseFail(Product product, PurchaseFailureReason failureReason,
PurchaseFailureDescription failureDescription = null)
{
if (failureDescription != null && failureDescription.reason == PurchaseFailureReason.DuplicateTransaction)
{
// ✅ 只处理消耗型商品
if (product.definition.type == ProductType.Consumable)
{
Debug.Log("DuplicateTransaction: 消耗型商品未消费,尝试补偿...");
var googlePlay = _extensionProvider.GetExtension<IGooglePlayStoreExtensions>();
googlePlay.RestoreTransactions((success, msg) =>
{
Debug.Log($"RestoreTransactions result: {success}, message: {msg}");
// 发奖励逻辑不要写这里,ProcessPurchase 会处理未完成订单
if (success)
{
_storeController.ConfirmPendingPurchase(product);
}
});
}
}
Debug.Log($"[google fail] HandleOnPurchaseFail 1 ");
if (_payData?.innerOrderId == null && !_payData.sku.Contains(".sub")) return;
Debug.Log($"[google fail] HandleOnPurchaseFail 2 {_payData?.innerOrderId} ");
GooglePayCancelInfo reqData = new();
if (failureDescription != null)
{
var receiptObj = JObject.Parse(failureDescription.item.Product.receipt);
var payload = JObject.Parse((string)receiptObj["Payload"]);
var jsonData = JObject.Parse((string)payload["json"]);
reqData.innerOrderId = _payData.innerOrderId;
reqData.reason = failureDescription.reason.ToString();
reqData.message = failureDescription.message;
reqData.productId = (string)jsonData["productId"];
}
else
{
reqData.innerOrderId = _payData.innerOrderId;
reqData.reason = failureReason.ToString();
}
GooglePayNet.GooglePayCancel<GooglePayCancelInfo>(reqData, (response) =>
{
string msg = ToFriendlyString(failureReason);
Debug.Log("[Google pay] HandleOnPurchaseFail---:" + response.IsSuccess + " reason: " + msg);
if (!_payData.sku.Contains(".sub"))
{
var innerdata = GetInnerIdData();
Debug.Log(
$"[Google pay] HandleOnPurchaseFail----- _payData.innerOrderId: {_payData.innerOrderId}");
innerdata.Remove(_payData.innerOrderId);
SaveInnerIdData(innerdata);
}
_failedCallback?.Invoke(msg);
_innerData = null;
_payData = null;
_successCallback?.Invoke(GooglePayBackType.Cancel, null);
});
}
private static string ToFriendlyString(PurchaseFailureReason reason)
{
Debug.Log($"ToFriendlyString 1 reason==={reason}");
return reason switch
{
PurchaseFailureReason.ProductUnavailable => "商品不可用",
PurchaseFailureReason.PurchasingUnavailable => "购买功能不可用",
PurchaseFailureReason.ExistingPurchasePending => "已有未完成的购买",
PurchaseFailureReason.SignatureInvalid => "签名验证失败",
PurchaseFailureReason.UserCancelled => "用户取消",
PurchaseFailureReason.PaymentDeclined => "支付被拒绝",
PurchaseFailureReason.DuplicateTransaction => "重复的交易ID",
PurchaseFailureReason.Unknown => "未知错误",
_ => $"未识别的错误: {(int)reason}"
};
}
#endregion
}
}
#else
namespace SGModule.GooglePay {
public class GooglePayManager: SingletonMonoBehaviour<GooglePayManager>{
public void StartPay() {
}
public string GetApplePayName(string key)
{
return "";
}
public void Purchase(GooglePayData payData, Action<GooglePayBackType> successCallback,
Action<string> failedCallback) {
var msg = "Apple Pay: Purchase Failed, No plugin is installed.";
Log.Info("[Apple IOS]",msg);
failedCallback?.Invoke(msg);
}
public void GoogleRestore(Action<bool, string> restoreCallback)
{
}
public void InitProduct(List<ProductConfig>configs, string packageName)
{
}
}
}
#endif
public class GoogleResponseData
{
[JsonProperty("expires_time")] public long expires_time;
[JsonProperty("sku")] public string sku;
}
public class GooglePayCheckInfo
{
public string innerOrderId;
public string orderId;
public string packageName;
public string productId;
public string purchaseToken;
public int purchaseState;
public bool test;
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6606e06edba94040a92bdc90b4ee6b1d
timeCreated: 1756198314
@@ -0,0 +1,80 @@
using SGModule.Common.Helper;
using SGModule.Net;
using UnityEngine.Events;
namespace SGModule.GooglePay
{
public static class GooglePayNet
{
#region GooglePay
/// <summary>
/// ios支付创建订单
/// </summary>
/// <param name="data"></param>
/// <param name="onCompleted"></param>
public static void GooglePayCreate<T>(GooglePayData data, UnityAction<ResponseData<T>> onCompleted = null)
{
NetKit.NetKit.Instance.Post<T>("shop/googlePayCreate", data,
response => { onCompleted?.Invoke(response); });
}
/// <summary>
/// ios支付取消订单
/// </summary>
/// <param name="data"></param>
/// <param name="onCompleted"></param>
public static void GooglePayCancel<T>(GooglePayCancelInfo data, UnityAction<ResponseData<T>> onCompleted = null)
{
NetKit.NetKit.Instance.Post<T>("shop/googlePayCancel", data,
response => { onCompleted?.Invoke(response); });
}
/// <summary>
/// ios支付验证订单
/// </summary>
/// <param name="transactionID">apple支付返回的订单id</param>
/// <param name="innerOrderId">内部订单id,创建订单时返回的</param>
/// <param name="infoData"></param>
/// <param name="key">包名</param>
/// <param name="onCompleted">回调</param>
public static void GooglePayCheck<T>(GooglePayCheckInfo infoData, string key, UnityAction<ResponseData<T>> onCompleted = null)
{
NetKit.NetKit.Instance.Post<T>("shop/googlePayCheck", infoData, response => { onCompleted?.Invoke(response); });
}
/// <summary>
/// ios支付订阅
/// </summary>
/// <param name="requestData">订阅请求数据</param>
/// <param name="onCompleted">回调</param>
public static void GoogleSubscribeCheck<T>(T requestData, UnityAction<ResponseData<T>> onCompleted = null)
{
Log.Info("[Google pay]",$" GoogleSubscribeCheck 开始...{requestData}");
NetKit.NetKit.Instance.Post<T>(
"shop/googleSubscribe",
requestData,
response =>
{
Log.Info("[Google pay]",$"GoogleSubscribeCheck 结束...{response.IsSuccess}");
onCompleted?.Invoke(response);
});
}
public static void GoogleSubscribeHistory<T>(T requestData, UnityAction<ResponseData<T>> onCompleted = null)
{
NetKit.NetKit.Instance.Post<T>(
"shop/subscribeHistory",
requestData,
response =>
{
onCompleted?.Invoke(response);
});
}
#endregion
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5151b63a9adc43ef9ab5e8d014c7140f
timeCreated: 1756199078
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 54d17c7a3e243184ba8890a66b001267
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
#if UNITY_IAP
using Newtonsoft.Json;
using SGModule.ConfigLoader;
using UnityEngine;
using UnityEngine.Purchasing;
namespace SGModule.GooglePay
{
[ConfigKey("applePay2")]
public class PayProductConfig
{
[JsonProperty("name")]
public string name;
[JsonProperty("sku")]
public string sku;
[JsonProperty("price")]
public float price;
[JsonProperty("type")]
public string type;
}
}
#endif
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d4b89b14416e451caafb0cc8a3a9c6fb
timeCreated: 1756199166