Project_WL/Assets/Script/Info/InappInfo.cs

427 lines
15 KiB
C#

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<InappInfo>(); DontDestroyOnLoad(_ins.gameObject); } return _ins; } }
private IStoreController m_storeController;
private PurchaseEventArgs m_PurchaseEventArgs;
Action m_success;
ShopItemListTableData m_Data;
private void Awake()
{
#if FGB_OneStore
var go = new GameObject("GaaIapCallbackManager").AddComponent<GaaIapCallbackManager>();
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(List<string> list)
{
#if FGB_OneStore
GaaIapCallManager.StartConnection("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCv1859fihjc+QXPQNYVfIFQQ6YJnjNUTYz7SAP00CYIefCwj4/D6LxGsLwtAJwn1jKng0QDHmyQUyO0k0QnLm7wqOwT0je+eD7wQ0G4BG3bETMOlYpAxpLFq3JmD1qMEemgrSgDldgvjWcyrdEzM01mr6q7+tXh4MBCt1ld1JFBQIDAQAB");
#else
ConfigurationBuilder cBuilder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
for (int iLoop = 0; iLoop < list.Count; ++iLoop)
cBuilder.AddProduct(list[iLoop], 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(ShopItemListTableData data, Action _act)
{
m_Data = data;
m_success = _act;
ServerInfo.Ins.Check_Token(() =>
{
#if FGB_OneStore
PurchaseFlowParams param = new PurchaseFlowParams();
param.productId = data.s_InappID;
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(data.s_InappID);
#endif
});
}
private void Excute_BuyItem()
{
var e = m_PurchaseEventArgs;
#if UNITY_EDITOR
UnityIAP_Process(true);
#elif UNITY_ANDROID // TODO 정인호 : 영수증 검증 너드나비스 서버로 변경 필요
// 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<IOSTEST>(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)
{
var sdata = ServerInfo.Ins.m_ServerData;
sdata.Add_ShopBuyCount(m_Data.n_ShopItemID);
sdata.Add_MissionCount(ePurpose.BUY_PAID_COUNT_ACC);
var inappid = m_PurchaseEventArgs.purchasedProduct.definition.id;
ServerInfo.Ins.Write_UnityInApp(inappid, () =>
{
NewGameUI.Ins.gos_noti[0].SetActive(true);
MyText.Show_CheckMailBox(); // 상품 우편 지급 팝업
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 = 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 = 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<string>();
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<ProductDetail> products = new List<ProductDetail>();
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<PurchaseData> purchases = new List<PurchaseData>();
private List<string> signatures = new List<string>();
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<PayloadData>(json);
payload.JsonData = JsonUtility.FromJson<JsonData>(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<GooglePurchase>(json);
purchase.PayloadData = PayloadData.FromJson(purchase.Payload);
return purchase;
}
}
// Unity 6: [SerializeField] is field-only (CS0592 on a class) — attribute removed 2026-09-05 (WL Unity 6 upgrade · no behavior change)
class IOSTEST { public string Payload, Store, TransactionID; }