유니티용 now.gg 결제 모듈과 함께 유니티 내에서 인앱 구매를 사용하실 수 있습니다.
방법:
now.gg 결제 유니티 모듈은 유니티 패키지 파일 nowgg-payments-login.unitypackage
에 포함되어 있습니다.
방법:
nowgg-payments-login.unitypackage
를 선택합니다.Assets/Plugins/Android
디렉토리에 다운로드 및 추가합니다.now.gg 결제 모듈을 임포트하고 종속성이 추가되면 이제 앱/게임에 now.gg 결제를 추가하실 수 있습니다.
now.gg IAP 서비스를 실행하려면 now.gg 플랫폼이 필요하며 유니티 네이티브 IAP(또는 기타 IAP 서비스)는 now.gg 플랫폼에서 실행되지 않을 때만 초기화 및 실행되어야 합니다.
플랫폼을 확인하고 앱이 now.gg 플랫폼에서 실행될 때 유니티 네이티브 IAP가 활성화되지 않도록 다음 코드를 추가합니다.
public void Start() { if (NowGG.Sdk.NowGGPaymentsSdkManager.IsNowGGIapAvailable()) return; // 여기에 코드를 작성합니다. }
아래는 유니티 내에서 호출할 수 있는 now.gg IAP 함수 예제입니다.
now.gg IAP가 포함된 클래스를 생성하고 인앱 구매를 초기화하는 데 사용할 게임 오브젝트에 추가합니다.
이 단계에서는 앱/게임에 인앱 구매 제품을 추가하고 SDK를 초기화할 수 있습니다.예를 들어, 다음 코드에서는 productId
‘coin1’과 ‘coin2’라는 두 개의 IAP 소모품 제품과 productId
‘monthlyPack’이라는 구독을 추가했습니다.
마찬가지로, nowStudio에 추가한 해당 productId
를 사용하여 다른 제품 및 구독을 추가할 수 있습니다. 아래 샘플 코드에 예시되어 있습니다:
public void Start() { // Only initialize Now.gg IAP if running on Now.gg platform if (!NowGG.Sdk.NowGGPaymentsSdkManager.IsNowGGIapAvailable()) return; // 소모품의 경우 NowGGProductBuilder.Instance.AddProduct("coin1", ProductType.Consumable); NowGGProductBuilder.Instance.AddProduct("coin2", ProductType.Consumable); // 구독의 경우 NowGGProductBuilder.Instance.AddProduct("monthlyPack", ProductType.Subscription); NowGGPaymentsSdkManager.Instance.OnInitSuccess += OnInitSuccess; NowGGPaymentsSdkManager.Instance.OnInitFailed += OnInitFailed; NowGGPaymentsSdkManager.Instance.OnPurchaseCompleted += OnPurchaseProduct; NowGGPaymentsSdkManager.Instance.OnPurchaseFailed += OnPurchaseFailed; NowGGPaymentsSdkManager.Instance.InitializeIap(PAYMENT_ID); }
설명:
NowGGProductBuilder
클래스에 추가되었습니다.PAYMENT_ID
를 사용하여 결제 모듈을 초기화하기 위해 NowGGPaymentsSdkManager
클래스의 InitializeIap
함수가 호출됩니다.초기화가 성공적으로 완료되면 productId
를 사용하여 상품의 세부정보를 얻을 수 있습니다.
아래는 예시입니다.
private void OnInitSuccess() { Debug.Log($"IAP init success"); Product coin1 = NowGGPaymentsSdkManager.Instance.GetProductWithID("coin1"); // now you can get product details using productId string price = coin1.price; string currencyCode = coin1.priceCurrencyCode; Product monthlyPack = NowGGPaymentsSdkManager.Instance.GetProductWithID("monthlyPack"); string monthlyPackSubscriptionPeriod = monthlyPack.subscriptionPeriod; } private void OnInitFailed(string reason) { Debug.Log($"IAP init failed {reason}"); }
참조:
상품의 세부정보를 확인한 후 구매를 시작하기 위해 아래와 같이 PurchaseProduct()
를 호출합니다.
public void PurchaseProduct(string productId, string developerPayload=null) { NowGGPaymentsSdkManager.Instance.PurchaseProduct(productId, developerPayload); }
참조:
방법:
private PurchaseProcessingResult OnPurchaseProduct(PurchasedProduct purchasedProduct) { string orderId = purchasedProduct.orderId; string purchaseToken = purchasedProduct.purchaseToken; string developerPayload = purchasedProduct.developerPayload; // 유저가 소모성 아이템을 구매했습니다. if (String.Equals(purchasedProduct.productId, "coin1", StringComparison.Ordinal)) { Debug.Log(string.Format("OnPurchaseProduct: PASS. Product: '{0}'", purchasedProduct.productId)); // 성공적으로 구매한 소모성 아이템인 100코인을 유저의 게임 내 재화에 추가합니다. // 예: coin += 100; } else if (String.Equals(purchasedProduct.productId, "coin2", StringComparison.Ordinal)) { Debug.Log(string.Format("OnPurchaseProduct: PASS. Product: '{0}'", purchasedProduct.productId)); // 성공적으로 구매한 소모성 아이템인 200코인을 유저의 게임 내 재화에 추가합니다. // 예: coin += 200; } else if (String.Equals(purchasedProduct.productId, "monthlyPack", StringComparison.Ordinal)) { Debug.Log(string.Format("OnPurchaseProduct: PASS. Product: '{0}'", purchasedProduct.productId)); Debug.Log("Subscription: " + purchasedProduct.subscriptionStatus + " " + purchasedProduct.subscriptionPeriod + " " + purchasedProduct.expiryTimeMillis + " " + purchasedProduct.subscriptionPurchaseDateMillis); if (purchasedProduct.subscriptionStatus == "ACTIVE" && purchaseProduct.isAcknowledged == false) { // 구독이 성공적으로 구매되었습니다. 구독의 혜택을 플레이어에게 전달하십시오. // 구매한 구독의 상태, 청구 기간, 만료를 반영하도록 UI를 업데이트하십시오. // 구매가 확인되었음을 인정하기 위해 PurchaseProcessingResult.Complete을 반환합니다 (구독). } } else { Debug.Log(string.Format("OnPurchaseProduct: FAIL. Unrecognized product: '{0}'", purchasedProduct.productId)); } // 해당 상품을 받았는지 또는 다음 앱 실행 시 애플리케이션이 해당 구매를 상기시켜야 하는지 여부를 나타내는 플래그를 반환합니다. // 다음에 앱/게임을 실행할 때 해당 구매에 대해 알림을 받기 위해 PurchaseProcessingResult.Pending을 반환합니다. // PurchaseProcessingResult.Complete를 반환하여 구매가 소비(소모품) 또는 승인(구독)되었으며 구매 혜택을 사용자에게 전달했음을 확인합니다. return PurchaseProcessingResult.Complete; }
참고:
OnPurchaseProduct
에서 PurchaseProcessingResult.Pending
을 반환해야 합니다.
참조:
purchaseToken
은 성공적인 구매 후에 생성되며 고유 식별자입니다.orderId
도 생성됩니다.
백엔드 서버가 있는 앱의 서버측 구매 소비 시 consumePurchase
API를 사용하시기 바랍니다.
구매를 인증한 후에는 소비됨으로 표시해야 합니다.
구매 소비에는 다음이 포함됩니다.
다음 샘플 코드는 consumePurchase
API를 통한 관련 요청 방법을 보여드립니다
import requests url = "https://payments-api.now.gg/v2/order/consumePurchase" headers = { "Authorization": "<payment_api_key_here>", "Content-Type": "application/x-www-form-urlencoded" } data = { "purchaseToken": "<purchase_token_here>", "productId": "<product_id_here>", // 멀티 스토어에만 필요 "developerPayload": "developerPayload", // 선택 사항 멀티 스토어에만 필요 "currency": "<currency>", // 멀티 스토어에만 필요 "type": "<store>" // xiaomi, onestore. 존재하지 않을 경우 기본값은 nowgg로 설정됩니다. } response = requests.post(url, headers=headers, data=data) print("응답 상태 코드:", response.status_code) print("응답 본문:", response.text)
curl --location --request POST 'https://payments-api.now.gg/v2/order/consumePurchase' \ --header 'Authorization: <payment_api_key_here>' \ --header 'Content-Type': 'application/x-www-form-urlencoded' \ --data '{ "purchaseToken": "<purchase_token_here>", "productId": "<product_id_here>", //멀티 스토어에만 필요 "developerPayload" : developerPayload, // 선택 사항, 멀티 스토어에만 필요 "currency": "<currency>", // 멀티 스토어에만 필요 "type": "<store>" // xiaomi | onestore 존재하지 않을 경우 기본값은 nowgg로 설정됩니다. }'
참조:
consumePurchase
API를 호출하기 전에 사용자에게 할당해야 합니다.Payments API Key
는 nowStudio의 자격 증명에 있습니다. (자세히)acknowledgePurchase
API는 백엔드 서버가 있는 앱의 서버 측 구매 승인을 위해 사용되어야 합니다.
구매를 확인한 후에는 이를 승인된 것으로 표시해야 합니다.
다음 샘플 코드는 acknowledgePurchase
API를 통한 관련 요청 방법을 보여드립니다
import requests url = "https://payments-api.now.gg/v2/seller/order/acknowledgepurchase" payload = 'purchaseToken=nowgg-_purchase_token' headers = { 'Authorization': 'payment_api_key_here', 'Content-Type': 'application/x-www-form-urlencoded' } response = requests.request("POST", url, headers=headers, data=payload) print(response.text)
참조:
Payments API Key
는 nowStudio의 자격 증명에 있습니다. (자세히)백엔드 서버에서 구매를 처리하거나 구현에 따라 다른 방법을 사용하여 구매를 완료해야 하는 경우 OnPurchaseProduct
에서 PurchaseProcessingResult.Pending
을 반환합니다.
구매 흐름을 완료하려면 ConfirmPendingPurchase
메서드를 사용하여 now.gg IAP 서비스에 앱이 구매를 기록했음을 알릴 수 있습니다.
public void ConfirmPendingPurchase(string purchasetoken, ProductType productType) { if (productType == ProductType.Consumable) { ConsumeProduct(purchasetoken); } else { AcknowledgePurchase(purchasetoken); } }
참조:
앱 백엔드 서버를 사용하여 구매 흐름을 완료하고 구매 권한을 부여하려면 다음을 호출하십시오:
대기 중인 구매를 위해 NowGGPaymentsSdkManager
클래스의 QueryPendingPurchases
를 호출하실 수 있으며 이때 OnPurchaseProduct
콜백을 통해 처리하실 수 있습니다.
NowGGPaymentsSdkManager.Instance.QueryPendingPurchases();
참조: OnPurchaseProduct.
구매할 추가 상품을 가져오거나 기존 상품의 세부 정보/메타데이터를 갱신하려면 아래와 같이 FetchAdditionalProducts
를 사용하실 수 있습니다.
var newProducts = new System.Collections.Generic.Dictionary<string, ProductType>(); newProducts.Add("coin2", ProductType.Consumable); newProducts.Add("coin3", ProductType.Consumable); NowGGPaymentsSdkManager.Instance.FetchAdditionalProducts(newProducts, () => { // 가져온 추가 상품을 이제 구매할 수 있습니다. Debug.Log($"Successfully fetched additional products"); Product coin1 = NowGGPaymentsSdkManager.Instance.GetProductWithID("coin1"); string price = coin1.price; string currencyCode = coin1.priceCurrencyCode; }, reason => { Debug.Log($"Fetching additional products failed: {reason}"); });
다음을 포함한 여러 가지 이유로 인해 구매가 실패할 수도 있습니다.
아래와 같이 실패한 구매를 확인하고 처리하실 수 있습니다.
public void OnPurchaseFailed(int errorCode, string errorMessage) { Debug.Log($"OnPurchaseFailed: errorCode: {errorCode} and msg: {errorMessage}"); }
중요:
OnPurchaseFailed
관련 응답 코드는 여기에서 참조하실 수 있습니다.구독 상태 업데이트에 대한 알림을 보내기 위해 SubscriptionStatusCallback
API를 제공하는 데 필요한 API입니다.
다음은 관련 워크플로입니다:
중요: Subscription Status Callback API.
다음 두 가지 방법 중 하나를 사용하여 구매를 인증하실 수 있습니다.
구매를 인증하는 첫 번째 방법은 verifyPurchase API를 사용하는 것으로 해당 API를 사용하여 백엔드 서버를 통해 구매를 인증하실 수 있습니다.
먼저 아래와 같이 앱 백엔드 서버에서 purchaseToken
와 함께 verifyPurchase API를 호출합니다.
import requests url = "https://payments-api.now.gg/v2/sellers/order/verifyPurchase" headers = { "Authorization": "<payment_api_key_here>", "Content-Type": "application/x-www-form-urlencoded" } data = { "purchaseToken": "<purchase_token_here>", "productId": "<product_id_here>", // 멀티 스토어에만 필요 "currency": "<currency>", // 멀티 스토어에만 필요 "type": "<store>" // 选项: xiaomi, onestore, amazon, huawei. 존재하지 않을 경우 기본값은 nowgg로 설정됩니다. } response = requests.post(url, headers=headers, data=data) print("响应状态码:", response.status_code) print("响应正文:", response.text)
curl --location --request POST 'https://payments-api.now.gg/v2/sellers/order/verifyPurchase' \ --header 'Authorization: <payment_api_key_here>' \ --header 'Content-Type': 'application/x-www-form-urlencoded' \ --data '{ "purchaseToken": "<purchase_token_here>", "productId": "<product_id_here>", // 멀티 스토어에만 필요 "currency": "<currency>", // 멀티 스토어에만 필요 "type": "<store>" // xiaomi | onestore | amazon | huawei 존재하지 않을 경우 기본값은 nowgg로 설정됩니다. }'
구매는 로컬 또는 백엔드 서버를 통해 인증하실 수 있으며, 이때 백엔드 서버를 사용하여 구매를 인증하시는 것을 권장해 드립니다.
아래와 같이 로컬 또는 백엔드 서버를 통해 인증하실 수 있으며 자세한 내용은 데모 프로젝트를 참조하시기 바랍니다.
private PurchaseProcessingResult OnPurchaseProduct(PurchasedProduct purchasedProduct) { // 로컬 인증을 하고 싶다면 해당 샘플 코드를 사용하실 수 있습니다. bool isValidPurchase = PurchaseVerification.Instance.VerifyPurchaseLocally( BASE_64_ENCODED_PUBLIC_KEY, purchasedProduct.originalJson, purchasedProduct.signature); // 백엔드 서버에서 구매를 인증하시는 것을 권장해 드립니다. // 인증을 위해 서명과 원본 데이터를 백엔드 서버로 보냅니다. PurchaseVerification.Instance.VerifyValidSignatureOnBackend( purchasedProduct.originalJson, purchasedProduct.signature); // 유저가 소모성 아이템을 구매했습니다. if (String.Equals(purchasedProduct.productId, "coin1", StringComparison.Ordinal)) { Debug.Log(string.Format("OnPurchaseProduct: PASS. Product: '{0}'", purchasedProduct.productId)); // 성공적으로 구매한 소모성 아이템인 100코인을 유저의 게임 내 재화에 추가합니다. // 예: coin += 100; } else if (String.Equals(purchasedProduct.productId, "coin2", StringComparison.Ordinal)) { Debug.Log(string.Format("OnPurchaseProduct: PASS. Product: '{0}'", purchasedProduct.productId)); // 성공적으로 구매한 소모성 아이템인 200코인을 유저의 게임 내 재화에 추가합니다 // 예: coin += 200; } else { Debug.Log(string.Format("OnPurchaseProduct: FAIL. Unrecognized product: '{0}'", purchasedProduct.productId)); } return PurchaseProcessingResult.Complete; }
다운로드 패키지에는 백엔드 서버를 사용하여 구매를 인증하는 샘플 코드가 포함되어 있습니다.
샘플 코드
구매 로컬 인증 관련 샘플 코드는 다운로드 패키지 내에서 확인해 보실 수 있습니다.
샘플 코드
PurchaseVerification
클래스의 VerifyPurchaseLocally
를 참조해 보시기 바랍니다.문서 Rev. 1.0