初始化UnityServer
using Firebase.Extensions; using RK_Runtime; using System; using System.Collections; using System.Collections.Generic; using Unity.Services.Core; using UnityEngine; public class UnityServiceTool : RK_Singleton<UnityServiceTool> { public bool IsInit = false; const string k_Environment = "production"; public override void StartUp() { base.StartUp(); Initialize(OnSuccess, OnError); } void Initialize(Action onSuccess, Action<string> onError) { try { var options = new InitializationOptions(); options.SetOption("Environment", k_Environment); UnityServices.InitializeAsync(options).ContinueWithOnMainThread(task => onSuccess()); } catch (Exception exception) { onError(exception.Message); } } void OnSuccess() { IsInit = true; var text = "Congratulations!\nUnity Gaming Services has been successfully initialized."; RK.Log.Log(text); MG_IAPurchaseManager.Instance.Initialize(0, false); } void OnError(string message) { var text = $"Unity Gaming Services failed to initialize with error: {message}."; RK.Log.LogError(text); } }
支付管理类
using cfg.Tpl; using RK_Runtime; using RK_Runtime.RK_Space_Http; using System.Collections.Generic; using System.Text; using UnityEngine; using UnityEngine.Purchasing; using UnityEngine.Purchasing.Extension; using SimpleJSON; using System; using System.Threading.Tasks; using Newtonsoft.Json; using RK_Runtime.RK_Space_Event; using RK_Runtime.Utility; //using UnityEngine.Purchasing.Security; //using DataTower.Core; public class MG_IAPurchaseManager : RK_MonoSingleton<MG_IAPurchaseManager>,IDetailedStoreListener { private IStoreController m_StoreController; // Unity 采购系统 private IExtensionProvider m_StoreExtensionProvider; // 商店特定的采购子系统. private Product m_PurchasedProduct; private int m_InitReTryTime = 0; private bool m_IsIniting = false; private string m_PurchasedProductID = string.Empty; private Dictionary<string,bool> m_OrderMap = new Dictionary<string,bool>(); class PayCheckReceiveJsonData { public int Code = 0; public string Data; } private void Start() { RK.Event.Add(OnEventApplicationPause); } [RK_EventHandle(EventDefine.EventApplicationPause)] private static void OnEventApplicationPause(object data) { bool pause = RK_ValueRef<bool>.GetValue(data); if (pause) { //PL_CommonLoadingPanel.HideLoading("PurchaseProduct"); } } public async Task Initialize(int trytime = 0, bool isLoading = true) { if (IsInitialized()) { return; } RK.Log.LogWarning("IAPurchaseManager initializing."); var orderStr = PlayerPrefs.GetString(PlayerPrefsKey.OrderInfoKey, ""); if (!string.IsNullOrEmpty(orderStr)) { var dic = JsonConvert.DeserializeObject<Dictionary<string,bool>>(orderStr); if (dic != null) { m_OrderMap = dic; } } m_IsIniting = true; m_InitReTryTime = trytime; if(isLoading) //PL_CommonLoadingPanel.ShowLoading("PayInitialize", delayTime: 0, when: () => { return !m_IsIniting; }); while (!UnityServiceTool.Instance.IsInit)//等待服务初始化 { await Task.Yield(); } var module = StandardPurchasingModule.Instance(); module.useFakeStoreUIMode = FakeStoreUIMode.StandardUser; module.useFakeStoreAlways = false; var builder = ConfigurationBuilder.Instance(module); for (int i = 0; i < SH_TableData.Instance.Datas.Goods.DataList.Count; i++) { if (!string.IsNullOrEmpty(SH_TableData.Instance.Datas.Goods.DataList[i].ProductID)) { builder.AddProduct(SH_TableData.Instance.Datas.Goods.DataList[i].ProductID, ProductType.Consumable); } } //StringBuilder stringBuilder = new StringBuilder(); //foreach (var item in builder.products) //{ // stringBuilder.AppendLine(item.id); //} //RK.Log.LogWarning(stringBuilder.ToString()); if (Application.platform == RuntimePlatform.Android) { var config = builder.Configure<IGooglePlayConfiguration>(); config.SetObfuscatedAccountId("UID:" + SH_UserData.Instance.LoginID); } UnityPurchasing.Initialize(this, builder); } public bool IsInitialized() { return m_StoreController != null && m_StoreExtensionProvider != null; } public void PurchaseProduct(string productId) { RK.Log.Log("Purchase:" + productId); //if (AotConfig.NoPay) //{ // SH_ShopData.Instance.BuySuccess(productId); // return; //} if (IsInitialized()) { if (m_PurchasedProduct != null) { //有订单正在购买中 //UT_CommonUtil.ShowErrorToast("TitleBuyConfirm"); CheckOrder(m_PurchasedProduct);//再去验证下 return; } Product product = m_StoreController.products.WithID(productId); if (product != null && product.availableToPurchase) { //PL_CommonLoadingPanel.ShowLoading("PurchaseProduct", delayTime: 0); BaseAdManager.Instance.SkipOpenAdTime++; m_PurchasedProduct = product; m_StoreController.InitiatePurchase(productId); } else { RK.Log.LogError(string.Format("Purchasing product asychronously: '{0}'", product.definition.id)); } } else { m_PurchasedProductID = productId; if (m_IsIniting) { m_InitReTryTime = 2; //PL_CommonLoadingPanel.ShowLoading("PayInitialize", delayTime: 0, when: () => { return !m_IsIniting; }); return; } Initialize(2); } } public void RestorePurchases() { if (!IsInitialized()) { Initialize(); return; } // If we are running on an Apple device ... if (Application.platform == RuntimePlatform.IPhonePlayer || Application.platform == RuntimePlatform.OSXPlayer) { // ... begin restoring purchases Debug.Log("RestorePurchases started ..."); // Fetch the Apple store-specific subsystem. var apple = m_StoreExtensionProvider.GetExtension<IAppleExtensions>(); // Begin the asynchronous process of restoring purchases. Expect a confirmation response in // the Action<bool> below, and ProcessPurchase if there are previously purchased products to restore. apple.RestoreTransactions((result, error) => { // The first phase of restoration. If no more responses are received on ProcessPurchase then // no purchases are available to be restored. if (result) { Debug.Log("RestorePurchases continuing: " + result + ". If no further messages, no purchases available to restore."); } else { RK.Log.LogWarning(error); } }); } // Otherwise ... else { // We are not running on an Apple device. No work is necessary to restore purchases. Debug.Log("RestorePurchases FAIL. Not supported on this platform. Current = " + Application.platform); } } /* * 验证 */ public void CheckOrder(Product product) { if (!product.hasReceipt) { m_PurchasedProduct = null; return; } RK.Log.Log("Success : " + product.ToString()); RK.Log.Log("Success receipt : " + product.receipt); List<string> produces = new List<string>(); List<string> orders = new List<string>(); bool validPurchase = true; // 假设对没有收据验证的平台有效。 bool hasProduct = false; // 假设对没有收据验证的平台有效。 //#if !UNITY_EDITOR // var validator = new CrossPlatformValidator(GooglePlayTangle.Data(), // AppleTangle.Data(), Application.identifier); // try { // //在 Google Play 上,结果中仅有一个商品 ID。 // //在 Apple 商店中,收据包含多个商品。 // var validateResult = validator.Validate(product.receipt); // //为便于参考,我们将收据列出 // Debug.Log("Receipt is valid. Contents:"); // //validateResult. // foreach (IPurchaseReceipt productReceipt in validateResult) { // produces.Add(productReceipt.productID); // orders.Add(productReceipt.transactionID); // } // } catch (IAPSecurityException) { // Debug.Log("Invalid receipt, not unlocking content"); // validPurchase = false; // } //#endif if (validPurchase) { List<string> lists = new List<string>(); for (int i = 0; i < produces.Count; i++) { if (!m_OrderMap.TryGetValue(orders[i], out var flat)) { SH_ShopData.Instance.BuySuccess(produces[i]); lists.Add(orders[i]); } } RK.Event.Call(EventDefine.EventUpdateUserInfo); m_StoreController.ConfirmPendingPurchase(product); m_PurchasedProduct = null; for (int i = 0; i < lists.Count; i++) { m_OrderMap.Add(lists[i], true); } PlayerPrefs.SetString(PlayerPrefsKey.OrderInfoKey, JsonConvert.SerializeObject(m_OrderMap)); PlayerPrefs.Save(); SH_UserData.Instance.ReqSaveUserInfo(()=>{ }); return; } else { m_PurchasedProduct = null; SH_ShopData.Instance.BuyFail(product.definition.id); } } public float GetPrice(string id) { return 0; } public void Release() { m_PurchasedProduct = null; m_StoreController = null; m_StoreExtensionProvider = null; m_PurchasedProductID = null; m_InitReTryTime = 0; m_IsIniting = false; } //----------------------------------IDetailedStoreListener---------------------------- public void OnInitialized(IStoreController controller, IExtensionProvider extensions) { m_IsIniting = false; m_InitReTryTime = 0; RK.Log.Log($"IAPurchaseManager Init Success"); m_StoreController = controller; m_StoreExtensionProvider = extensions; if (Application.platform == RuntimePlatform.IPhonePlayer) { extensions.GetExtension<IAppleExtensions>().SetApplicationUsername("特定的格式-UUID 映射uid"); } if (!string.IsNullOrEmpty(m_PurchasedProductID)) { PurchaseProduct(m_PurchasedProductID); m_PurchasedProductID = null; } } public void OnInitializeFailed(InitializationFailureReason error, string message) { if (m_InitReTryTime > 0) { RK.Log.Log($"IAPurchaseManager Init : {error} {message} retry "); m_InitReTryTime--; Initialize(m_InitReTryTime); } else { m_IsIniting = false; RK.Log.LogError($"IAPurchaseManager Init : {error} {message} "); if (!string.IsNullOrEmpty(m_PurchasedProductID)) { //弹出提示 //UT_CommonUtil.ShowErrorToast(RK_I18NLanguageUtil.GetI18nString("PaymentFailed")); } } } public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent) { //让服务端去确认 m_PurchasedProduct = purchaseEvent.purchasedProduct; CheckOrder(m_PurchasedProduct); return PurchaseProcessingResult.Pending; } public void OnPurchaseFailed(Product product, PurchaseFailureDescription failureDescription) { m_PurchasedProduct = null; RK.Log.Log(failureDescription.reason.ToString() + ":" + failureDescription.message); //CommonUtil.ShowToast(failureDescription.message); switch (failureDescription.reason) { case PurchaseFailureReason.UserCancelled: //UT_CommonUtil.ShowToast(RK_I18NLanguageUtil.GetI18nString("ButtonCancle")); break; default: UT_CommonUtil.ShowErrorToast(failureDescription.reason.ToString()); break; } // Dictionary<string, string> param = new Dictionary<string, string>(); // param.Add("platform", Application.platform == RuntimePlatform.IPhonePlayer ? "ios" : "android"); // param.Add("productId", failureDescription.productId); // param.Add("transactionID", product.transactionID); // param.Add("appleOriginalTransactionID", product.appleOriginalTransactionID); // param.Add("reason", failureDescription.reason.ToString()); // param.Add("message", failureDescription.message); // // string json = JsonConvert.SerializeObject(param); SH_ShopData.Instance.BuyFail(product.definition.id); } public void OnInitializeFailed(InitializationFailureReason error) { throw new System.NotImplementedException(); } public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason) { m_PurchasedProduct = null; RK.Log.Log(failureReason.ToString()); //CommonUtil.ShowToast(failureDescription.message); switch (failureReason) { case PurchaseFailureReason.UserCancelled: //UT_CommonUtil.ShowToast(RK_I18NLanguageUtil.GetI18nString("ButtonCancle")); break; default: UT_CommonUtil.ShowErrorToast(failureReason.ToString()); break; } // Dictionary<string, string> param = new Dictionary<string, string>(); // param.Add("platform", Application.platform == RuntimePlatform.IPhonePlayer ? "ios" : "android"); // param.Add("productId", failureDescription.productId); // param.Add("transactionID", product.transactionID); // param.Add("appleOriginalTransactionID", product.appleOriginalTransactionID); // param.Add("reason", failureDescription.reason.ToString()); // param.Add("message", failureDescription.message); // // string json = JsonConvert.SerializeObject(param); SH_ShopData.Instance.BuyFail(product.definition.id); } }