using System; using UnityEngine; using UnityEngine.Purchasing; using System.Collections.Generic; using PlayFab; using PlayFab.ClientModels; using UnityEngine.Purchasing.Extension; #if FGB_OneStore using Gaa; #endif public class InappInfo : MonoBehaviour, IDetailedStoreListener { private static InappInfo _ins; public static InappInfo Ins { get { if (_ins == null) { _ins = new GameObject("InappInfo").AddComponent(); DontDestroyOnLoad(_ins.gameObject); } return _ins; } } private IStoreController m_storeController; private PurchaseEventArgs m_PurchaseEventArgs; Action m_success; private void Awake() { #if FGB_OneStore var go = new GameObject("GaaIapCallbackManager").AddComponent(); DontDestroyOnLoad(go.gameObject); GaaIapCallbackManager.PurchaseClientStateEvent += PurchaseClientStateEvent; GaaIapCallbackManager.LoginFlowEvent += LoginFlowEvent; GaaIapCallbackManager.UpdateOrInstallFlowEvent += UpdateOrInstallFlowEvent; GaaIapCallbackManager.ProductDetailsSuccessEvent += ProductDetailsSuccessEvent; GaaIapCallbackManager.ProductDetailsErrorEvent += ProductDetailsErrorEvent; GaaIapCallbackManager.PurchaseUpdatedErrorEvent += PurchaseUpdatedErrorEvent; GaaIapCallbackManager.PurchaseUpdatedSuccessEvent += PurchaseUpdatedSuccessEvent; GaaIapCallbackManager.ConsumeErrorEvent += ConsumeErrorEvent; GaaIapCallbackManager.ConsumeSuccessEvent += ConsumeSuccessEvent; GaaIapCallbackManager.QueryPurchasesSuccessEvent += QueryPurchasesSuccessEvent; GaaIapCallbackManager.QueryPurchasesErrorEvent += QueryPurchasesErrorEvent; #endif } private void OnDestroy() { #if FGB_OneStore GaaIapCallbackManager.PurchaseClientStateEvent -= PurchaseClientStateEvent; GaaIapCallbackManager.LoginFlowEvent -= LoginFlowEvent; GaaIapCallbackManager.UpdateOrInstallFlowEvent -= UpdateOrInstallFlowEvent; GaaIapCallbackManager.ProductDetailsSuccessEvent -= ProductDetailsSuccessEvent; GaaIapCallbackManager.ProductDetailsErrorEvent -= ProductDetailsErrorEvent; GaaIapCallbackManager.PurchaseUpdatedErrorEvent -= PurchaseUpdatedErrorEvent; GaaIapCallbackManager.PurchaseUpdatedSuccessEvent -= PurchaseUpdatedSuccessEvent; GaaIapCallbackManager.ConsumeErrorEvent -= ConsumeErrorEvent; GaaIapCallbackManager.ConsumeSuccessEvent -= ConsumeSuccessEvent; GaaIapCallManager.Destroy(); #endif } public string Get_Price_orNull(string _id) { #if FGB_OneStore var p = products.Find(f => f.productId == _id); if (p != null) return DSUtil.Format("{0}원", p.price); #else if (m_storeController != null) { var p = m_storeController.products.WithID(_id); if (p != null) return p.metadata.localizedPriceString; } #endif return null; } public void Set(Action success) { m_success = success; #if FGB_OneStore GaaIapCallManager.StartConnection("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCv1859fihjc+QXPQNYVfIFQQ6YJnjNUTYz7SAP00CYIefCwj4/D6LxGsLwtAJwn1jKng0QDHmyQUyO0k0QnLm7wqOwT0je+eD7wQ0G4BG3bETMOlYpAxpLFq3JmD1qMEemgrSgDldgvjWcyrdEzM01mr6q7+tXh4MBCt1ld1JFBQIDAQAB"); #else ConfigurationBuilder cBuilder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance()); var list = table_shop.Ins.Get_DataList(); for (int iLoop = 0; iLoop < list.Count; ++iLoop) { var shopdata = list[iLoop] as ShopTableData; if (!string.IsNullOrEmpty(shopdata.InappID)) cBuilder.AddProduct(shopdata.InappID, ProductType.Consumable); } UnityPurchasing.Initialize(this, cBuilder); #endif } public void Check_Retrieved() { // 미지급된 상품이 있는 지 체크 #if FGB_OneStore GaaIapCallManager.QueryPurchases(Gaa.ProductType.INAPP); #else if (m_PurchaseEventArgs != null) { Debug.Log("Check_Retrieved " + m_PurchaseEventArgs.purchasedProduct.metadata.localizedTitle); Excute_BuyItem(); } #endif } public void Buy_InappItem(string _id, Action _act) { m_success = _act; ServerInfo.Ins.Check_CanBuyInapp(() => { #if FGB_OneStore PurchaseFlowParams param = new PurchaseFlowParams(); param.productId = _id; param.productType = Gaa.ProductType.INAPP; //param.devPayload = "결제 후에 데이터의 정합성과 부가 데이터를 확인하기 위해 사용할 수 있습니다."; //param.productName = ""; // optional //param.gameUserId = ""; // promotion //param.promotionApplicable = false; // promotion GaaIapCallManager.LaunchPurchaseFlow(param); #else if (m_storeController != null) m_storeController.InitiatePurchase(_id); #endif }); } private void Excute_BuyItem() { var e = m_PurchaseEventArgs; #if UNITY_EDITOR UnityIAP_Process(true); #elif UNITY_ANDROID // Deserialize receipt var googleReceipt = GooglePurchase.FromJson(e.purchasedProduct.receipt); // Invoke receipt validation // This will not only validate a receipt, but will also grant player corresponding items // only if receipt is valid. PlayFabClientAPI.ValidateGooglePlayPurchase(new ValidateGooglePlayPurchaseRequest() { // Pass in currency code in ISO format CurrencyCode = e.purchasedProduct.metadata.isoCurrencyCode, // Convert and set Purchase price PurchasePrice = (uint)(e.purchasedProduct.metadata.localizedPrice * 100), // Pass in the receipt ReceiptJson = googleReceipt.PayloadData.json, // Pass in the signature Signature = googleReceipt.PayloadData.signature }, result => { UnityIAP_Process(true); }, error => { UnityIAP_Process(false, error.GenerateErrorReport()); }); #else var json = JsonUtility.FromJson(e.purchasedProduct.receipt); PlayFabClientAPI.ValidateIOSReceipt(new ValidateIOSReceiptRequest { CurrencyCode = e.purchasedProduct.metadata.isoCurrencyCode, PurchasePrice = (int)e.purchasedProduct.metadata.localizedPrice * 100, ReceiptData = json.Payload, }, result => { UnityIAP_Process(true); }, error => { UnityIAP_Process(false, error.GenerateErrorReport()); }); #endif } void UnityIAP_Process(bool _success, string _GenerateErrorReport = "") { if (_success) { table_shop.Ins.Buy_Inapp(m_PurchaseEventArgs.purchasedProduct.definition.id, () => { m_storeController.ConfirmPendingPurchase(m_PurchaseEventArgs.purchasedProduct); m_PurchaseEventArgs = null; m_success?.Invoke(); m_success = null; }); } else { NetWait.Ins.Set(false); Popup.Ins.Set(ePopupType.One, -100, null, null, _GenerateErrorReport); Debug.Log("Validation failed: " + _GenerateErrorReport); } } public void OnInitializeFailed(InitializationFailureReason error) { //DSUtil.Format("Inapp OnInitializeFailed : {0}", error); m_storeController = null; m_success?.Invoke(); // 일단 로그인 시킴 m_success = null; } public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent) { m_PurchaseEventArgs = purchaseEvent; Excute_BuyItem(); return PurchaseProcessingResult.Pending; } public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason) { NetWait.Ins.Set(false); if (failureReason != PurchaseFailureReason.UserCancelled) Popup.Ins.Set(ePopupType.One, -101, null, null, failureReason); } public void OnInitialized(IStoreController controller, IExtensionProvider extensions) { Debug.Log("Inapp OnInitialized"); m_storeController = controller; m_success?.Invoke(); m_success = null; } public void OnInitializeFailed(InitializationFailureReason error, string message) { //Popup.Ins.Set(ePopupType.One, -102, null, null, error, message); } public void OnPurchaseFailed(Product product, PurchaseFailureDescription failureDescription) { NetWait.Ins.Set(false); if (failureDescription.reason != PurchaseFailureReason.UserCancelled) Popup.Ins.Set(ePopupType.One, -101, null, null, failureDescription.message); } #if FGB_OneStore // StartConnection 콜백 함수 void PurchaseClientStateEvent(IapResult iapResult) { if (iapResult.IsSuccess()) { // StartConnection 성공 var list = table_shop.Ins.Get_DataList(); var all_products = new List(); for (int iLoop = 0; iLoop < list.Count; ++iLoop) { var shopdata = list[iLoop] as ShopTableData; if (!string.IsNullOrEmpty(shopdata.InappID)) all_products.Add(shopdata.InappID); } GaaIapCallManager.QueryProductDetails(all_products.ToArray(), Gaa.ProductType.ALL); } else if (iapResult.code == ResponseCode.RESULT_NEED_UPDATE) { Debug.Log("원스토어 RESULT_NEED_UPDATE"); Popup.Ins.Set(ePopupType.Two, "원스토어 업데이트가 필요합니다.\n\n업데이트 하시겠습니까?", () => { GaaIapCallManager.LaunchUpdateOrInstallFlow(); }, DSUtil.Quit); } else if (iapResult.code == ResponseCode.RESULT_NEED_LOGIN) { Debug.Log("원스토어 RESULT_NEED_LOGIN"); Popup.Ins.Set(ePopupType.Two, "원스토어 로그인이 필요합니다.\n\n로그인 하시겠습니까?", () => { GaaIapCallManager.LaunchLoginFlow(); }, DSUtil.Quit); } else { m_success?.Invoke(); m_success = null; // 테스트 : 원스토어 SDK 무시 로그인 //Debug.Log("원스토어 에러\n" + iapResult.message + "\n" + iapResult.code); //Popup.Ins.Set(ePopupType.One, iapResult.message + "\n(계속 이 메시지가 보인다면, 원스토어 앱의 데이터를 제거해 주세요.)", DSUtil.Quit, DSUtil.Quit); } } void LoginFlowEvent(IapResult iapResult) { Debug.Log("원스토어 LoginFlowEvent " + iapResult.message); if (iapResult.IsSuccess()) Set(m_success); else PurchaseClientStateEvent(iapResult); } void UpdateOrInstallFlowEvent(IapResult iapResult) { Debug.Log("원스토어 UpdateOrInstallFlowEvent " + iapResult.message); if (iapResult.IsSuccess()) Set(m_success); else PurchaseClientStateEvent(iapResult); } List products = new List(); void ProductDetailsSuccessEvent(ProductDetail productDetail, int count, int totalCount) { Debug.Log("원스토어 ProductDetailsSuccessEvent " + productDetail.productId + "\n" + count + "\n" + totalCount); if (count == 1) { products.Clear(); } products.Add(productDetail); if (count == totalCount) { m_success?.Invoke(); m_success = null; } } private List purchases = new List(); private List signatures = new List(); private void PurchaseUpdatedSuccessEvent(PurchaseData purchaseData, string signature, int count, int totalCount) { if (purchaseData != null) { if (count == 1) { purchases.Clear(); signatures.Clear(); } purchases.Add(purchaseData); signatures.Add(signature); if (count == totalCount) { table_shop.Ins.Buy_OneStore(purchaseData, () => { m_success?.Invoke(); m_success = null; GaaIapCallManager.Consume(purchaseData, ""); }); } } else { NetWait.Ins.Set(false); PurchaseUpdatedErrorEvent(new IapResult { message = "" }); } } private void PurchaseUpdatedErrorEvent(IapResult obj) { NetWait.Ins.Set(false); Popup.Ins.Set(ePopupType.One, obj.message); } void ProductDetailsErrorEvent(IapResult iapResult) { Debug.Log("원스토어 ProductDetailsErrorEvent " + iapResult.message); PurchaseClientStateEvent(iapResult); } private void ConsumeSuccessEvent(PurchaseData obj) { Debug.Log("원스토어 ConsumeSuccessEvent"); } private void ConsumeErrorEvent(IapResult obj) { Debug.Log("원스토어 ConsumeErrorEvent : " + obj.message); } private void QueryPurchasesErrorEvent(IapResult obj) { Debug.Log("원스토어 QueryPurchasesErrorEvent : " + obj.message); } private void QueryPurchasesSuccessEvent(PurchaseData arg1, string arg2, int arg3, int arg4) { table_shop.Ins.Buy_OneStore(arg1, () => { m_success?.Invoke(); m_success = null; GaaIapCallManager.Consume(arg1, ""); }); } #endif } public class JsonData { // JSON Fields, ! Case-sensitive public string orderId; public string packageName; public string productId; public long purchaseTime; public int purchaseState; public string purchaseToken; } public class PayloadData { public JsonData JsonData; // JSON Fields, ! Case-sensitive public string signature; public string json; public static PayloadData FromJson(string json) { var payload = JsonUtility.FromJson(json); payload.JsonData = JsonUtility.FromJson(payload.json); return payload; } } public class GooglePurchase { public PayloadData PayloadData; // JSON Fields, ! Case-sensitive public string Store; public string TransactionID; public string Payload; public static GooglePurchase FromJson(string json) { var purchase = JsonUtility.FromJson(json); purchase.PayloadData = PayloadData.FromJson(purchase.Payload); return purchase; } } [SerializeField] class IOSTEST { public string Payload, Store, TransactionID; }