提交模块化内容

This commit is contained in:
2026-06-04 10:22:38 +08:00
parent 6b8b282347
commit fcf9128dd3
623 changed files with 38437 additions and 2 deletions
+3
View File
@@ -0,0 +1,3 @@
# ApplePay
2025 年 05 月 24 日 V1.0.0 提交初始版本 applepay 模块,该模块功能依赖通用模块,网络模块和数据模块,请一起拉取
+7
View File
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f92f9691c788c414a82e03722722293e
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 10ce64fc727c4edeb97e73ad29ef5eab
timeCreated: 1747906541
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f2da583c874f4b13acc3eb54eaf5a428
timeCreated: 1747996053
@@ -0,0 +1,43 @@
using Newtonsoft.Json;
namespace SGModule.ApplePay
{
public class ApplePayData
{
[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;
}
public class AppleCheckData
{
[JsonProperty("signedPayload")]
public string signedPayload;
[JsonProperty("innerOrderId")]
public string innerOrderId;
}
public class AppleSubscribeData
{
[JsonProperty("signedPayload")]
public string signedPayload;
[JsonProperty("sku")]
public string sku;
[JsonProperty("currency")]
public string currency;
[JsonProperty("amount")]
public int amount;
[JsonProperty("expires_time")]
public long expires_time;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9dcbc72e1537449aaea5b71d67e7bf85
timeCreated: 1747996070
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 69666ded8fdc4244a0d43d25f7831bca
timeCreated: 1747906570
@@ -0,0 +1,18 @@
namespace SGModule.ApplePay
{
public enum ApplePayBackType
{
/// <summary>
///创建支付订单
/// </summary>
Create,
/// <summary>
///验证支付订单
/// </summary>
Check,
/// <summary>
///取消支付订单
/// </summary>
Cancel,
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e83ae38d5d0e4880836c55d708e7083c
timeCreated: 1747995062
@@ -0,0 +1,661 @@
using SGModule.Common.Base;
using System;
using System.Collections.Generic;
using SGModule.Common.Helper;
using SGModule.NetKit;
using Newtonsoft.Json;
#if UNITY_IOS && 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.ApplePay
{
public class ApplePayManager : SingletonMonoBehaviour<ApplePayManager>, IDetailedStoreListener
{
private IStoreController _storeController;
private static IExtensionProvider _extensionProvider;
private static IAppleExtensions _appleExtension;
private Action<string> _failedCallback;
private Action<ApplePayBackType, AppleResponseData> _successCallback;
private Dictionary<string, (string id, string type)> _products = new Dictionary<string, (string, string)>();
private ApplePayData _payData;
private string _packageName;
private float _lastPayAttemptTime;
public void SendDebugToServer(string error, string stackTrace) {
// ErrorLogKit.Send("debug", error, stackTrace,SuperApplication.Instance.attribution);
}
private Dictionary<string, ProductConfig> _productConfigs = new Dictionary<string, ProductConfig>();
/// <summary>
/// 通过 ProductConfig 数组初始化商品
/// </summary>
public void InitProduct(List<ProductConfig> configs, string packageName, Action<ApplePayBackType, AppleResponseData> successCallback)
{
var module = StandardPurchasingModule.Instance();
ConfigurationBuilder builder = ConfigurationBuilder.Instance(module);
_successCallback = successCallback;
_packageName = packageName;
SendDebugToServer("[Apple pay] InitProduct 开始------", Environment.StackTrace);
try
{
foreach (var config in configs)
{
// Debug.Log( $"[Apple pay] InitProduct ------{config.sku} , {config.type} ");
if (Enum.TryParse<UnityEngine.Purchasing.ProductType>(config.type, true, out var productType))
{
_productConfigs.Add(config.sku, config);
builder.AddProduct(config.sku, productType);
}
else
{
SendDebugToServer($"无法解析 ProductType: {config.type}", Environment.StackTrace);
Debug.LogError($"无法解析 ProductType: {config.type}");
// 可根据需要处理默认类型或跳过该商品
}
}
SendDebugToServer("[Apple pay] InitProduct 结束------", Environment.StackTrace);
UnityPurchasing.Initialize(this, builder);
}
catch (Exception e)
{
SendDebugToServer($" 初始化商品 失败 InitProduct: {e.Message}", Environment.StackTrace);
Console.WriteLine(e);
throw;
}
Debug.Log( $"[Apple pay] InitProduct -----2 ");
}
private void SetPayData(string sku)
{
var payData = GetPayData(sku);
_payData = payData;
}
private ApplePayData GetPayData(string sku)
{
if (_productConfigs.TryGetValue(sku, out var data))
{
Debug.Log( $"[Apple pay] InitProduct ------{data.sku} , {data.type} ");
return new ApplePayData
{
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 = 60f; // 1分钟超时
while (Time.time - startTime < timeout)
{
// 如果_payData已经为null,停止检测
if (_payData == null)
{
yield break;
}
yield return null;
}
// 1分钟后检查,如果_payData仍然不为null,则设为null
if (_payData != 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<ApplePayBackType, AppleResponseData> successCallback, Action<string> failedCallback)
{
Debug.Log( $"[Apple Pay] Purchase: {JsonConvert.SerializeObject(_payData)}");
SendDebugToServer("[Apple pay] 购买 Purchase ------", Environment.StackTrace);
if (Time.time - _lastPayAttemptTime < 5)
{
failedCallback?.Invoke("Clicks are too frequent");
return;
}
_lastPayAttemptTime = Time.time;
Debug.Log( $"[Apple Pay] Purchase-00---------{JsonConvert.SerializeObject(_payData)}");
if (_payData != null)
{
// 启动超时检测
StartPayDataTimeoutCheck();
return;
}
Debug.Log( $"[Apple Pay] Purchase-1---------");
if (!IsInitialized())
{
failedCallback?.Invoke("Not Initialized");
return;
}
Debug.Log( $"[Apple Pay] Purchase-2---------");
var product = _storeController.products.WithID(sku);
if (product == null || !product.availableToPurchase)
{
failedCallback?.Invoke("Either is not found or is not available for purchase");
return;
}
_successCallback = successCallback;
_failedCallback = failedCallback;
SetPayData(sku);
_storeController.InitiatePurchase(product);
Debug.Log( $"[Apple Pay] Purchase-3---------");
if (_payData != null)
{
var payData = new ApplePayData
{
sku = sku,
currency = "USD",
amount = _payData.amount,
};
ApplePayNet.ApplePayCreate<ApplePayData>(payData, (response) =>
{
Debug.Log( $"[Apple Pay] Purchase-4---------");
if (response.IsSuccess)
{
_successCallback?.Invoke(ApplePayBackType.Create, null);
}
if (_payData != null) _payData.innerOrderId = response.Data.innerOrderId;
SendDebugToServer($"[Apple Pay] Purchase-5-------创建内部ID innerOrderId--{_payData.innerOrderId}", Environment.StackTrace);
Debug.Log( $"[Apple Pay] Purchase-5-------innerOrderId--{_payData.innerOrderId}");
});
}
}
/// <summary>
/// IOS恢复内购
/// 会在删除应用后,第一次安装是自动恢复
/// </summary>
/// <param name="restoreCallback">恢复回调</param>
public void AppleRestore(Action<bool, string> restoreCallback)
{
if (!IsInitialized())
{
Debug.LogWarning("[ApplePay] IAppleExtensions 未初始化");
return;
}
Debug.Log( "[ApplePay] 用户手动恢复购买");
_appleExtension.RestoreTransactions((success, error) =>
{
if (success)
{
Debug.Log( "[Apple Pay] Restore Transactions 成功");
// 这里会触发 ProcessPurchase 回调
restoreCallback(true, error);
}
else
{
Debug.LogError($"[Apple Pay] Restore Transactions 失败: {error}");
// 可以提示用户重试
}
});
}
#region
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent)
{
SendDebugToServer($"[Apple pay] 购买成功回调 Purchase ---{JsonConvert.SerializeObject(purchaseEvent.purchasedProduct)}---", Environment.StackTrace);
var product = purchaseEvent.purchasedProduct;
var productType = product.definition.type;
var sku = product.definition.id;
var receipt = product.receipt;
Debug.Log(
$" ProcessPurchase 1 Purchase: {JsonConvert.SerializeObject(purchaseEvent.purchasedProduct)}");
if (purchaseEvent is not { purchasedProduct: not null })
{
Debug.LogError("[Apple Pay] ProcessPurchase 2 : purchaseEvent 或 purchasedProduct 为 null");
return PurchaseProcessingResult.Complete;
}
Debug.Log( $"购买商品类型: {productType}, SKU: {sku}");
if (productType == ProductType.Subscription)
{
SendDebugToServer($"[Apple pay] 购买商品类型 Purchase ---{productType}-{sku}--", Environment.StackTrace);
// 服务器验证
UploadReceiptForValidation(sku, product.transactionID, isSuccess =>
{
if (isSuccess)
{
// 验证成功后的逻辑
// 验证成功,完成购买
_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(product.transactionID, isSuccess =>
{
if (isSuccess)
{
// 验证成功,完成购买
_storeController.ConfirmPendingPurchase(product);
}
});
return PurchaseProcessingResult.Pending;
}
/// <summary>
/// 支付测试代码
/// </summary>
/// <param name="type"></param>
/// <param name="sku"></param>
/// <param name="transactionID"></param>
public void ApplePayTest(ProductType type, string sku, string transactionID, Action<ApplePayBackType, AppleResponseData> successCallback)
{
SetPayData(sku);
Debug.Log( $"[ApplePay] 测试支付 type: {type}, sku: {sku}, transactionID: {transactionID}" );
_successCallback = successCallback;
if (type == ProductType.Subscription)
{
// 服务器验证
UploadReceiptForValidation(sku, transactionID, isSuccess =>
{
if (isSuccess)
{
Debug.Log( "订阅商品验证成功");
}
});
return;
}
if (type == ProductType.NonConsumable)
{
Debug.Log(
$" 识别到非消耗性商品 ----{DataMgr.ApplePayTransactionID.Value.Contains(transactionID)}");
if (DataMgr.ApplePayTransactionID.Value.Contains(transactionID))
{
return;
}
DataMgr.ApplePayTransactionID.Value.Add(transactionID);
}
// 普通商品直接处理
HandlePurchaseSuccess(transactionID, isSuccess =>
{
if (isSuccess)
{
Debug.Log( "普通商品验证成功");
}
},true);
}
//服务器验证
private void UploadReceiptForValidation(string sku, string transactionID, Action<bool> onValidationComplete)
{
Debug.Log( "识别到订阅商品,准备进行订阅验证");
SendDebugToServer($"[Apple pay] 识别到订阅商品,准备进行订阅验证", Environment.StackTrace);
var productConfig = GetPayData(sku);
if (productConfig != null)
{
Debug.Log( $"订阅商品ID: {sku} transactionID: {transactionID} _payData.amount: {productConfig.amount}");
SendDebugToServer($"订阅商品ID: {sku} transactionID: {transactionID} _payData.amount: {productConfig.amount}", Environment.StackTrace);
ApplePayNet.AppleSubscribeCheck<AppleSubscribeData>(
transactionID,
sku,
productConfig.amount,
_packageName,
response =>
{
bool isSuccess = response.IsSuccess;
// 在这里返回验证结果
onValidationComplete?.Invoke(isSuccess);
_payData = null;
if (isSuccess)
{
Debug.Log( "订阅验证成功");
SendDebugToServer($"订阅验证成功", Environment.StackTrace);
_successCallback?.Invoke(ApplePayBackType.Check, new AppleResponseData()
{
expires_time = response.Data.expires_time,
sku = sku
});
}
else
{
Debug.LogWarning("[Apple Pay] 订阅验证失败");
}
});
}
}
/// <summary>
/// 支付成功后的本地处理(订阅和普通商品共用)
/// </summary>
private void HandlePurchaseSuccess(string transactionID, Action<bool> onValidationComplete, bool isTest = false)
{
var payDataJson = GetApplePayData();
Debug.Log( $" HandlePurchaseSuccess payDataJson: {JsonConvert.SerializeObject(payDataJson)}");
var statusDictionary = JsonConvert.DeserializeObject<Dictionary<string, ApplePayData>>(payDataJson)
?? new Dictionary<string, ApplePayData>();
SendDebugToServer($"普通商品 HandlePurchaseSuccess: {transactionID}", Environment.StackTrace);
if (!statusDictionary.ContainsKey(transactionID))
{
Debug.Log( $"记录新交易 transactionID: {transactionID}");
Debug.Log( $"-----_payData: {JsonConvert.SerializeObject(_payData)}" );
if (_payData == null || string.IsNullOrWhiteSpace(_payData.innerOrderId))
{
Debug.LogWarning("[Apple Pay] _payData 为空或 innerOrderId 无效");
return;
}
statusDictionary.Add(transactionID, _payData);
SaveApplePayData(statusDictionary);
_payData = null;
}
if (statusDictionary.TryGetValue(transactionID, out var cValue))
{
if (!string.IsNullOrWhiteSpace(cValue.innerOrderId) || isTest)
{
ApplePaySuccess(transactionID, onValidationComplete);
}
}
}
private void SaveApplePayData(Dictionary<string, ApplePayData> 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 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( $"ApplePayRequest 1 payDataJson: {JsonConvert.SerializeObject(payDataJson)}");
SendDebugToServer($"验单 普通商品: {transactionID}", Environment.StackTrace);
var statusDictionary = JsonConvert.DeserializeObject<Dictionary<string, ApplePayData>>(payDataJson);
if (statusDictionary.ContainsKey(transactionID))
{
Debug.Log( $"ApplePayRequest 2 transactionID: {transactionID}");
var data = statusDictionary[transactionID];
ApplePayNet.ApplePayCheck<ApplePayData>(transactionID, data.innerOrderId, _packageName, (response) =>
{
Debug.Log(
$"ApplePayRequest 3 response.IsSuccess: {JsonConvert.SerializeObject(response)}");
onValidationComplete?.Invoke(response.IsSuccess);
if (response.IsSuccess)
{
_successCallback(ApplePayBackType.Check, null);
statusDictionary.Remove(transactionID);
// 保存更新后的数据
SaveApplePayData(statusDictionary);
}
if (!new List<int>() { 1021, 1026, 1027, 1028 }.Contains(response.Code))
{
}
else
{
statusDictionary.Remove(transactionID);
// 保存更新后的数据
SaveApplePayData(statusDictionary);
}
});
}
}
#endregion
#region
private bool IsInitialized()
{
Debug.Log( "[barry] check IsInitialized======:");
return _storeController != null && _extensionProvider != null;
}
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
_storeController = controller;
_extensionProvider = extensions;
_appleExtension = extensions.GetExtension<IAppleExtensions>();
}
public void OnInitializeFailed(InitializationFailureReason error)
{
Debug.Log( "[barry] OnInitializeFailed1 Reason:" + error);
// throw new NotImplementedException();
}
public void OnInitializeFailed(InitializationFailureReason error, string message)
{
Debug.Log( "[barry] OnInitializeFailed2 Reason:" + error);
Debug.Log( "[barry] OnInitializeFailed2 message:" + message);
// throw new NotImplementedException();
}
#endregion
#region
public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
{
Debug.Log( " OnPurchaseFailed===1==:");
HandleOnPurchaseFail(failureReason);
}
public void OnPurchaseFailed(Product product, PurchaseFailureDescription failureDescription)
{
Debug.Log( "OnPurchaseFailed===2==:");
HandleOnPurchaseFail(failureDescription.reason);
}
private void HandleOnPurchaseFail(PurchaseFailureReason failureReason)
{
Debug.Log( $" HandleOnPurchaseFail 1 ");
if (_payData == null) return;
Debug.Log( $" HandleOnPurchaseFail 2 ");
ApplePayNet.ApplePayCancel<ApplePayData>(_payData, (response) =>
{
string msg = ToFriendlyString(failureReason);
Debug.Log( "[barry] HandleOnPurchaseFail:" + response.IsSuccess + " reason: " + msg);
_failedCallback?.Invoke(msg);
_payData = null;
_successCallback?.Invoke(ApplePayBackType.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.ApplePay {
public class ApplePayManager: SingletonMonoBehaviour<ApplePayManager>{
public void StartPay() {
}
public string GetApplePayName(string key)
{
return "";
}
public void Purchase(ApplePayData payData, Action<ApplePayBackType> successCallback,
Action<string> failedCallback) {
var msg = "Apple Pay: Purchase Failed, No plugin is installed.";
Log.Info("[Apple IOS]",msg);
failedCallback?.Invoke(msg);
}
public void AppleRestore(Action<bool, string> restoreCallback)
{
}
// public void InitProduct(List<ProductConfig>configs, string packageName)
// {
// }
}
}
#endif
public class AppleResponseData
{
[JsonProperty("expires_time")]
public long expires_time;
[JsonProperty("sku")]
public string sku;
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8478e5310ad64f23a3805cd8a3fa024f
timeCreated: 1747907338
@@ -0,0 +1,95 @@
using SGModule.Common.Helper;
using SGModule.Net;
using UnityEngine.Events;
namespace SGModule.ApplePay
{
public static class ApplePayNet
{
#region IOSPay
/// <summary>
/// ios支付创建订单
/// </summary>
/// <param name="data"></param>
/// <param name="onCompleted"></param>
public static void ApplePayCreate<T>(ApplePayData data, UnityAction<ResponseData<T>> onCompleted = null)
{
NetKit.NetKit.Instance.Post<T>("shop/applePayCreate", data,
response => { onCompleted?.Invoke(response); });
}
/// <summary>
/// ios支付取消订单
/// </summary>
/// <param name="data"></param>
/// <param name="onCompleted"></param>
public static void ApplePayCancel<T>(ApplePayData data, UnityAction<ResponseData<T>> onCompleted = null)
{
NetKit.NetKit.Instance.Post<T>("shop/applePayCancel", data,
response => { onCompleted?.Invoke(response); });
}
public static void ApplePaySubscriptionHistory<T>(UnityAction<ResponseData<T>> onCompleted = null)
{
NetKit.NetKit.Instance.Post<T>("shop/subscribeHistory", null,
response => { onCompleted?.Invoke(response); });
}
// public static void ApplePaySubscriptionCheck<T>(HistoryObject obj,UnityAction<ResponseData<T>> onCompleted = null)
// {
// NetKit.NetKit.Instance.Post<T>("shop/subscribeCheck", obj,
// response => { onCompleted?.Invoke(response); });
// }
/// <summary>
/// ios支付验证订单
/// </summary>
/// <param name="transactionID">apple支付返回的订单id</param>
/// <param name="innerOrderId">内部订单id,创建订单时返回的</param>
/// <param name="key">包名</param>
/// <param name="onCompleted">回调</param>
public static void ApplePayCheck<T>(string transactionID, string innerOrderId,
string key, UnityAction<ResponseData<T>> onCompleted = null)
{
var test = new AppleCheckData
{
signedPayload = Common.Helper.Cryptor.Encrypt(transactionID, key),
innerOrderId = innerOrderId
};
NetKit.NetKit.Instance.Post<T>("shop/applePayCheck", test,
response => { onCompleted?.Invoke(response); });
}
/// <summary>
/// ios支付订阅
/// </summary>
/// <param name="transactionID">apple支付返回的订单id</param>
/// <param name="sku">商品id</param>
/// <param name="amount">价格</param>
/// <param name="key">包名</param>
/// <param name="onCompleted">回调</param>
public static void AppleSubscribeCheck<T>(string transactionID, string sku, int amount,
string key, UnityAction<ResponseData<T>> onCompleted = null)
{
var test = new AppleSubscribeData
{
signedPayload = Common.Helper.Cryptor.Encrypt(transactionID, key),
sku = sku,
amount = amount,
currency = "USD"
};
Log.Info("[Apple pay]", $" AppleSubscribeCheck 开始...{sku}");
NetKit.NetKit.Instance.Post<T>(
"shop/appleSubscribe",
test,
response =>
{
Log.Info("[Apple pay]", $"AppleSubscribeCheck 结束...{response.IsSuccess}");
onCompleted?.Invoke(response);
});
}
#endregion
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 760f78942ee949a9af90bc8ac6710be7
timeCreated: 1747996461
@@ -0,0 +1,22 @@
#if UNITY_IOS && UNITY_IAP
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Purchasing;
namespace SGModule.ApplePay
{
[System.Serializable]
public class ProductConfig
{
[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: bab80a35d16a48e6856d995e175b82d3
timeCreated: 1747911023