using System;
using PhxhSDK;
using UnityEngine;
using Unity.Services.Core;
using UnityEngine.Purchasing;
using System.Collections.Generic;
using UnityEngine.Purchasing.Security;
using UnityEngine.Purchasing.Extension;
using Unity.Services.Core.Environments;
///
/// 苹果支付
///
public class IAPHandle : IDetailedStoreListener
{
private const string Environment = "production";
public Action SendReceiptAction;
public Action SetApplicationUseId;
public Action OnBreakPurchase;
public bool ClientVerify;
public List ConsumableGoods;
public List NonConsumableGoods;
private Dictionary _pendingDic = new Dictionary();
private IStoreController _controller;
private IExtensionProvider _extensions;
private IAppleExtensions _appleExtensions;
private IGooglePlayStoreExtensions _googlePlayStoreExtensions;
private Action _onPurchaseSuccess;
private Action _onPurchaseFail;
private Action> _onRestore;
private bool _isInitialized;
///
/// 当前购买商品
///
private string _curProduct;
public IAPHandle()
{
try
{
InitUnityService();
}
catch (Exception exception)
{
DebugUtil.LogError("异常:" + exception);
}
}
#region 初始化
async void InitUnityService()
{
try
{
Debug.Log("初始化Unity服务器");
var options = new InitializationOptions().SetEnvironmentName(Environment);
await UnityServices.InitializeAsync(options).ContinueWith(task => OnInitUnityServiceSuccess());
StandardPurchasingModule.Instance().useFakeStoreAlways = true;
}
catch (Exception exception)
{
OnInitUnityServiceError(exception.Message);
}
}
private void OnInitUnityServiceError(string message)
{
DebugUtil.LogError("unity server initialization failed, Error: " + message);
}
private void OnInitUnityServiceSuccess()
{
Debug.Log("unity server initialization successful !!");
}
///
/// 初始化商品
///
public void InitIap()
{
if (ConsumableGoods == null && NonConsumableGoods == null)
return;
Debug.Log("初始化IAP商品及 UnityPurchasing");
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
//Add Product
foreach (var consumableGoods in ConsumableGoods)
{
Debug.Log($"添加消耗商品:{consumableGoods}");
builder.AddProduct(consumableGoods, ProductType.Consumable);
}
foreach (var nonConsumableGoods in NonConsumableGoods)
{
Debug.Log($"添加非消耗商品:{nonConsumableGoods}");
builder.AddProduct(nonConsumableGoods, ProductType.NonConsumable);
}
UnityPurchasing.Initialize(this, builder);
}
///
/// IStoreListener 初始化
///
void IStoreListener.OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
_controller = controller;
_extensions = extensions;
_appleExtensions = extensions.GetExtension();
_googlePlayStoreExtensions = extensions.GetExtension();
if (string.IsNullOrEmpty(SDKManager.Instance.ApplicationUserName))
{
Guid uid = Guid.NewGuid();
SDKManager.Instance.ApplicationUserName = uid.ToString();
}
_appleExtensions.SetApplicationUsername(SDKManager.Instance.ApplicationUserName);
Debug.Log("IAP initialization successful");
Debug.Log("用户 UUID :" + SDKManager.Instance.ApplicationUserName);
_isInitialized = true;
}
///
/// IAP 初始化失败
///
void IStoreListener.OnInitializeFailed(InitializationFailureReason error)
{
DebugUtil.LogError("Unity IAP遇到不可恢复的初始化错误调用,请检查配置或设备设置中是否禁用ipa");
}
///
/// IAP 初始化失败
///
void IStoreListener.OnInitializeFailed(InitializationFailureReason error, string message)
{
DebugUtil.LogError("IAP OnInitializeFailed reason : " + message);
switch (error)
{
case InitializationFailureReason.AppNotKnown:
DebugUtil.LogError("IAP Is your App correctly uploaded on the relevant publisher console?");
break;
case InitializationFailureReason.PurchasingUnavailable:
DebugUtil.LogError("IAP Billing disabled!");
break;
case InitializationFailureReason.NoProductsAvailable:
DebugUtil.LogError("IAP No products available for purchase!");
break;
default:
throw new ArgumentOutOfRangeException(nameof(error), error, message);
}
}
#endregion
#region 购买
///
/// IAP 购买商品
///
public void BuyGoods(string productId, string actorId, Action onPurchaseSuccess, Action onPurchaseFail)
{
try
{
Debug.Log("购买商品: " + productId);
#if !UNITY_EDITOR
if (!_isInitialized || Application.internetReachability == NetworkReachability.NotReachable)
return;
WaitingForServer.Instance.EventWaiting(WaitingForServer.EventName.Pay, false);
_onPurchaseSuccess = onPurchaseSuccess;
_onPurchaseFail = onPurchaseFail;
_controller.InitiatePurchase(productId, actorId);
#else
DebugUtil.Log("请在真实环境下测试");
#endif
}
catch (Exception e)
{
DebugUtil.LogError("IAPHandle.BuyGoods, product: {0}, Error: {1}", productId, e);
WaitingForServer.Instance.EventDone(WaitingForServer.EventName.Pay);
}
}
///
/// IAP 购买成功
///
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e)
{
#if UNITY_IOS || UNITY_ANDROID
var validator = new CrossPlatformValidator(GooglePlayTangle.Data(),
AppleTangle.Data(), Application.identifier);
DebugUtil.Log("Google Play Public Key: " + GooglePlayTangle.Data());
DebugUtil.Log("Apple Public Key: " + AppleTangle.Data());
try
{
var result = validator.Validate(e.purchasedProduct.receipt);
DebugUtil.Log("Receipt is valid. Contents:");
foreach (IPurchaseReceipt productReceipt in result)
{
if (!IAPManager.Instance.ProductDic.TryGetValue(productReceipt.productID, out var productID))
continue;
Debug.Log($"productID: {productReceipt.productID}");
Debug.Log($"purchaseDate: {productReceipt.purchaseDate}");
AppleInAppPurchaseReceipt apple = productReceipt as AppleInAppPurchaseReceipt;
if (null != apple)
{
_curProduct = productReceipt.productID;
Debug.Log("iOS Receipt: " + apple.originalTransactionIdentifier);
if (!ClientVerify)
{
if (!IAPManager.Instance.OwnedNonConsumableGood(_curProduct))
{
AddPendingOrder(apple.originalTransactionIdentifier, e.purchasedProduct);
SendReceipt(apple.originalTransactionIdentifier, _curProduct);
}
else
{
Debug.Log($"非消耗品商品{_curProduct}已购买过");
}
}
else
{
_onPurchaseSuccess?.Invoke(_curProduct);
}
}
GooglePlayReceipt google = productReceipt as GooglePlayReceipt;
if (null != google)
{
_curProduct = productReceipt.productID;
// 这是 Google 的订单 ID。
// 请注意,在沙盒中测试时此项为 null,因为 Google 的沙盒不提供订单 ID。
Debug.Log($"Google transactionID: {google.transactionID}");
Debug.Log($"Google purchaseState: {google.purchaseState}");
Debug.Log($"Google purchaseToken: {google.purchaseToken}");
//TODO 谷歌服务器验证 待测试 待确定验证哪个参数
if (!ClientVerify)
{
if (!IAPManager.Instance.OwnedNonConsumableGood(_curProduct))
{
AddPendingOrder(google.transactionID, e.purchasedProduct);
SendReceipt(google.transactionID, _curProduct);
}
}
else
{
_onPurchaseSuccess?.Invoke(_curProduct);
}
}
}
}
catch (Exception exception)
{
DebugUtil.LogError("ProcessPurchase Result Error: " + exception);
}
if (ClientVerify)
return PurchaseProcessingResult.Complete;
return PurchaseProcessingResult.Pending;
#else
return PurchaseProcessingResult.Complete;
#endif
}
///
/// IAP 购买失败
///
void IStoreListener.OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
{
WaitingForServer.Instance.EventDone(WaitingForServer.EventName.Pay);
if (failureReason == PurchaseFailureReason.PurchasingUnavailable)
{
DebugUtil.LogError("可能在设备设置中禁用了 IAP");
}
_curProduct = null;
_onPurchaseFail?.Invoke();
DebugUtil.LogError("Purchase of [{0}] failed for this reason: {1}", product.definition.id, failureReason);
}
///
/// IAP 购买失败
///
public void OnPurchaseFailed(Product product, PurchaseFailureDescription failureDescription)
{
WaitingForServer.Instance.EventDone(WaitingForServer.EventName.Pay);
DebugUtil.LogError("购买 {0} 失败, 原因: {1} ", failureDescription.productId, failureDescription.message);
}
///
/// 向服务器发送收据验证
///
private void SendReceipt(string receipt, string product)
{
if (SendReceiptAction == null)
DebugUtil.LogError("SendReceiptAction 为空");
SendReceiptAction?.Invoke(receipt, product);
}
///
/// 收集待验证凭证
///
void AddPendingOrder(string appleReceipt, Product product)
{
Debug.Log("添加待验证收据:{appleReceipt}");
_pendingDic.TryAdd(appleReceipt, product);
}
///
/// 服务器验证完成移除待验证凭证
///
public void RemovePendingOrder(string receipt)
{
if (_pendingDic.ContainsKey(receipt))
{
_controller.ConfirmPendingPurchase(_pendingDic[receipt]);
_pendingDic.Remove(receipt);
Debug.Log($"移除待验证收据:{receipt}, 待验证凭证还有: {_pendingDic.Count}");
}
if (_pendingDic.Count == 0)
{
Debug.Log($"订单 {receipt} 已完结, 购买的商品: {_curProduct}");
_onPurchaseSuccess?.Invoke(_curProduct);
}
}
///
/// Debug
///
public void ConfirmPending()
{
foreach (var goods in _pendingDic)
{
_controller.ConfirmPendingPurchase(goods.Value);
Debug.Log($" 完成订单:{goods.Key}");
}
_pendingDic.Clear();
}
#endregion
//TODO 待完善 测试
///
/// 恢复交易
///
public void RestorePurchase(Action> onRestorePurchase)
{
if (!_isInitialized)
return;
_onRestore = onRestorePurchase;
var apple = _extensions.GetExtension();
apple.RestoreTransactions(HandleRestored);
}
private void HandleRestored(bool result, string message)
{
var tempRestoreGoods = new List();
if (result)
{
Debug.Log("恢复购买成功");
foreach (var product in _controller.products.all)
{
if (product.hasReceipt)
{
tempRestoreGoods.Add(product.definition.id);
Debug.Log("Products to be restored: " + product.definition.id);
}
}
_onRestore?.Invoke(tempRestoreGoods);
}
else
{
DebugUtil.LogWarning("购买恢复失败: {0}", message);
}
}
string GetAppReceipt()
{
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
string receipt = builder.Configure().appReceipt;
return receipt;
}
bool CanMakePayments()
{
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
return builder.Configure().canMakePayments;
}
///
/// 根据ID获取商品价格
///
public string GetGoodPrice(string productID)
{
var product = _controller.products.WithID(productID);
if (product != null)
{
string price = product.metadata.localizedPriceString;
DebugUtil.Log("Product price: " + price);
return price;
}
DebugUtil.LogError("Product not found");
return null;
}
}