2024-12-15 01:39:39 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
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(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<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)
|
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
2024-12-23 00:54:51 +00:00
|
|
|
//DSUtil.Format("Inapp OnInitializeFailed : {0}", error);
|
2024-12-15 01:39:39 +00:00
|
|
|
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)
|
|
|
|
|
{
|
2024-12-23 00:54:51 +00:00
|
|
|
//Popup.Ins.Set(ePopupType.One, -102, null, null, error, message);
|
2024-12-15 01:39:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
class IOSTEST { public string Payload, Store, TransactionID; }
|