ここではUnityでアプリ内決済機能を使用するために必要な設定方法についてご案内いたします。 Gamebaseは、一つの統合された決済APIを提供することで、ゲームで簡単に各ストアのアプリ内決済を連携することができるようサポートします。
[注意]
外部パッケージで決済関連処理がある場合、 Gamebase決済機能が正常に動作しない可能性があります。
AndroidやiOSでアプリ内決済機能を設定する方法は、次のドキュメントをご参考ください。
アイテムの購入は大きく分けて決済フロー、消費フロー、再処理フローの3つがあります。 決済フローは、次のような順序で実装してください。
未消費決済履歴リストに値がある場合、次のような順序でConsume Flowを進行してください。
[注意]
アイテムの重複支給が発生しないように、ゲームサーバーで必ず重複支給の有無をチェックしてください。
購入したいアイテムのitemSeqを利用して次のAPIを呼び出し、購入をリクエストします。 ゲームユーザーが購入をキャンセルする場合、PURCHASE_USER_CANCELEDエラーが返されます。
API
Supported Platforms ■ UNITY_IOS ■ UNITY_ANDROID
static void RequestPurchase(string gamebaseProductId, GamebaseCallback.GamebaseDelegate<GamebaseResponse.Purchase.PurchasableReceipt> callback)
static void RequestPurchase(string gamebaseProductId, string payload, GamebaseCallback.GamebaseDelegate<GamebaseResponse.Purchase.PurchasableReceipt> callback)
Example
public void RequestPurchase(string gamebaseProductId)
{
Gamebase.Purchase.RequestPurchase(gamebaseProductId, (purchasableReceipt, error) =>
{
if (Gamebase.IsSuccess(error))
{
Debug.Log("Purchase succeeded.");
}
else
{
if (error.code == (int)GamebaseErrorCode.PURCHASE_USER_CANCELED)
{
Debug.Log("User canceled purchase.");
}
else
{
Debug.Log(string.Format("Purchase failed. error is {0}", error));
}
}
});
}
public void RequestPurchase(string gamebaseProductId)
{
string userPayload = "{\"description\":\"This is example\",\"channelId\":\"delta\",\"characterId\":\"abc\"}";
Gamebase.Purchase.RequestPurchase(gamebaseProductId, userPayload, (purchasableReceipt, error) =>
{
if (Gamebase.IsSuccess(error))
{
Debug.Log("Purchase succeeded.");
// userPayload value entered when calling API
string payload = purchasableReceipt.payload
}
else
{
if (error.code == (int)GamebaseErrorCode.PURCHASE_USER_CANCELED)
{
Debug.Log("User canceled purchase.");
}
else
{
Debug.Log(string.Format("Purchase failed. error is {0}", error));
}
}
});
}
VO
public class PurchasableReceipt
{
/// <summary>
/// 購入したアイテムの商品IDです。
/// </summary>
public string gamebaseProductId;
/// <summary>
/// itemSeqで商品を購入するLegacy API用の識別子です。
/// </summary>
public long itemSeq;
/// <summary>
/// 購入した商品の価格です。
/// </summary>
public float price;
/// <summary>
/// 通貨コードです。
/// </summary>
public string currency;
/// <summary>
/// 決済識別子です。
/// purchaseTokenと一緒にConsumeサーバーAPIを呼び出すのに使用する重要な情報です。
///
/// 注意:Consume APIは、ゲームサーバーで呼び出してください!
/// <para/><see href="https://docs.toast.com/en/Game/Gamebase/en/api-guide/#purchase-iap">Consume API</see>
/// </summary>
public string paymentSeq;
/// <summary>
/// 決済識別子です。
/// paymentSeqと一緒にConsumeサーバーAPIを呼び出すために使用する重要な情報です。
/// Consume APIでは「accessToken」という名前のパラメータで渡す必要があります。
///
/// 注意:Consume APIは、ゲームサーバーで呼び出してください!
/// <para/><see href="https://docs.toast.com/en/Game/Gamebase/en/api-guide/#purchase-iap">Consume API</see>
/// </summary>
public string purchaseToken;
/// <summary>
/// Google、Appleのようにストアコンソールに登録された商品IDです。
/// </summary>
public string marketItemId;
/// <summary>
/// 商品タイプです。次の値を使用できます。
/// * UNKNOWN:認識できないタイプ。Gamebase SDKをアップデートするか、Gamebaseサポートへお問い合わせください。
/// * CONSUMABLE:消費性商品。
/// * AUTO_RENEWABLE:購読型商品。
/// * CONSUMABLE_AUTO_RENEWABLE:購読型商品を購入したユーザーに、定期的に消費が可能な商品を支給したい場合に使われる「消費が可能な購読商品」。
/// <para/><see cref="GamebasePurchase.ProductType"/>
/// </summary>
public string productType;
/// <summary>
/// 商品を購入したUser ID。
/// 商品を購入していないUser IDでログインした場合、購入したアイテムを獲得できません。
/// </summary>
public string userId;
/// <summary>
/// ストアの決済識別子です。
/// </summary>
public string paymentId;
/// <summary>
/// 購読商品は更新されるごとにpaymentIdが変更されます。
/// このフィールドは最初に購読商品を決済した時のpaymentIdを伝えます。
/// ストアによっては、決済サーバーの状態に応じた値が存在しない場合があるため
/// 常に有効な値を保障するわけではありません。
/// </summary>
public string originalPaymentId;
/// <summary>
/// 商品を購入した時刻です。(epoch time)
/// </summary>
public long purchaseTime;
/// <summary>
/// 購読が終了する時刻です。(epoch time)
/// </summary>
public long expiryTime;
/// <summary>
/// 決済したストアコードです。
/// GamebaseStoreCodeクラスでストアコードリストを確認できます。
/// </summary>
public string storeCode;
/// <summary>
/// Gamebase.Purchase.requestPurchase API呼び出し時にpayloadで渡された値です。
///
/// スストアサーバーの状態によっては情報が失われる場合があるため、使用を推奨しません。
/// </summary>
public string payload;
/// <summary>
/// プロモーション決済かどうか
/// - (Android) Gamebase決済サーバーで一時的に検証ロジックをオフにする場合にはfalseのみ出力されるため、常に有効な値が保障されません。
/// </summary>
public bool isPromotion;
/// <summary>
/// テスト決済かどうか
/// - (Android) Gamebase決済サーバーで一時的に検証ロジックをオフにする場合にはfalseのみ出力されるため、常に有効な値が保障されません。
/// </summary>
public bool isTestPurchase;
}
アイテムリストを照会したい場合、次のAPIを呼び出します。 コールバックで返されるリストの中にはそれぞれ各アイテムの情報が含まれています。
API
Supported Platforms ■ UNITY_IOS ■ UNITY_ANDROID
static void RequestItemListPurchasable(GamebaseCallback.GamebaseDelegate<List<GamebaseResponse.Purchase.PurchasableItem>> callback)
Example
public void RequestItemListPurchasable()
{
Gamebase.Purchase.RequestItemListPurchasable((purchasableItemList, error) =>
{
if (Gamebase.IsSuccess(error))
{
Debug.Log("Get list succeeded.");
}
else
{
Debug.Log(string.Format("Get list failed. error is {0}", error));
}
});
}
VO
public class PurchasableItem
{
/// <summary>
/// Gamebaseコンソールに登録された商品IDです。
/// Gamebase.Purchase.requestPurchase APIで商品を購入する時に使用されます。
/// </summary>
public string gamebaseProductId;
/// <summary>
/// itemSeqで商品を購入するLegacy API用の識別子です。
/// </summary>
public long itemSeq;
/// <summary>
/// 商品の価格です。
/// </summary>
public float price;
/// <summary>
/// 通貨コードです。
/// </summary>
public string currency;
/// <summary>
/// Gamebaseコンソールに登録されている商品名です。
/// </summary>
public string itemName;
/// <summary>
/// Google、Appleのようにストアコンソールに登録された商品IDです。
/// </summary>
public string marketItemId;
/// <summary>
/// 商品タイプです。次の値を使用できます。
/// * UNKNOWN:認識できないタイプ。Gamebase SDKをアップデートするか、Gamebaseサポートへお問い合わせください。
/// * CONSUMABLE:消費性商品。
/// * AUTORENEWABLE:購読型商品。
/// * CONSUMABLE_AUTO_RENEWABLE:購読型商品を購入したユーザーに、定期的に消費が可能な商品を支給したい場合に使われる「消費が可能な購読商品」。
/// <para/><see cref="GamebasePurchase.ProductType"/>
/// </summary>
public string productType;
/// <summary>
/// 通貨記号が含まれるローカライズされた価格情報です。
/// </summary>
public string localizedPrice;
/// <summary>
/// ストアコンソールに登録されているローカライズされた商品名です。
/// </summary>
public string localizedTitle;
/// <summary>
/// ストアコンソールに登録されているローカライズされた商品説明です。
/// </summary>
public string localizedDescription;
/// <summary>
/// Gamebaseコンソールで該当商品の「使用有無」を表します。
/// </summary>
public bool isActive;
}
アイテムを購入したが、正常にアイテムが消費(配送、支給)されなかった未消費決済履歴をリクエストします。 未消費決済履歴があある場合はゲームサーバー(アイテムサーバー)にリクエストして、アイテムを配送(支給)するように処理する必要があります。 正常に決済が完了しなかった場合、再処理の役割も担うため、次の状況で呼び出してください。
GamebaseRequest.Purchase.PurchasableConfiguration
API | Mandatory(M) / Optional(O) | Description |
---|---|---|
allStores | O | 同じUserIDで他のストアにて購入した未消費履歴も変換します。 デフォルト値はfalseです。 |
API
Supported Platforms ■ UNITY_IOS ■ UNITY_ANDROID
static void RequestItemListOfNotConsumed(GamebaseRequest.Purchase.PurchasableConfiguration configuration, GamebaseCallback.GamebaseDelegate<List<GamebaseResponse.Purchase.PurchasableReceipt>> callback)
Example
public void RequestItemListOfNotConsumedSample(bool allStores)
{
var configuration = new GamebaseRequest.Purchase.PurchasableConfiguration
{
allStores = allStores
};
Gamebase.Purchase.RequestItemListOfNotConsumed(configuration, (purchasableReceiptList, error) =>
{
if (Gamebase.IsSuccess(error))
{
Debug.Log("Get list succeeded.");
// Should Deal With This non-consumed Items.
// Send this item list to the game(item) server for consuming item.
}
else
{
Debug.Log(string.Format("RequestItemListOfNotConsumed failed. error is {0}", error));
}
});
}
現在のユーザーIDで有効になっている定期購入リストを照会します。 決済が完了した定期購入商品(自動更新型定期購入、自動更新型消費性定期購入商品)は、期間が終了するまで照会できます。
[注意]
現在AndroidではGoogle Playストアでのみサブスクリプション商品をサポートしています。
GamebaseRequest.Purchase.PurchasableConfiguration
API | Mandatory(M) / Optional(O) | Description |
---|---|---|
allStores | O | 同じUserIDで他のストアにて購入した未消費履歴も変換します。 デフォルト値はfalseです。 |
API
Supported Platforms ■ UNITY_IOS ■ UNITY_ANDROID
static void RequestActivatedPurchases(GamebaseRequest.Purchase.PurchasableConfiguration configuration, GamebaseCallback.GamebaseDelegate<List<GamebaseResponse.Purchase.PurchasableReceipt>> callback)
Example
public void RequestActivatedPurchasesSample(bool allStores)
{
var configuration = new GamebaseRequest.Purchase.PurchasableConfiguration
{
allStores = allStores
};
Gamebase.Purchase.RequestActivatedPurchases(configuration, (purchasableReceiptList, error) =>
{
if (Gamebase.IsSuccess(error) == true)
{
Debug.Log("RequestItemListPurchasable succeeded");
foreach (GamebaseResponse.Purchase.PurchasableReceipt purchasableReceipt in purchasableReceiptList)
{
var message = new StringBuilder();
message.AppendLine(string.Format("gamebaseProductId:{0}", purchasableReceipt.gamebaseProductId));
message.AppendLine(string.Format("price:{0}", purchasableReceipt.price));
message.AppendLine(string.Format("currency:{0}", purchasableReceipt.currency));
// You will need paymentSeq and purchaseToken when calling the Consume API.
// Refer to the following document for the Consume API.
// https://docs.toast.com/en/Game/Gamebase/en/api-guide/#purchaseiap
message.AppendLine(string.Format("paymentSeq:{0}", purchasableReceipt.paymentSeq));
message.AppendLine(string.Format("purchaseToken:{0}", purchasableReceipt.purchaseToken));
message.AppendLine(string.Format("marketItemId:{0}", purchasableReceipt.marketItemId));
Debug.Log(message);
}
}
else
{
// Check the error code and handle the error appropriately.
Debug.Log(string.Format("RequestActivatedPurchases failed. error is {0}", error));
}
});
}
現在のユーザーID基準でサブスクリプション商品の状態を照会します。 コールバックで返されるリストにはサブスクリプション商品の情報が含まれています。
[注意]
- 以下のガイドに従って購読イベントを設定すると、購読ステータスコードが正常に返されます。
- Game > Gamebase > ストアコンソールガイド > Googleコンソールガイド > Googleシステム内リアルタイム購読情報イベント配信設定
- イベント設定を行っていない状態で購入したサブスクリプション商品のステータスコードは常に0(PURCHASED)が返されます。
- 現在、サブスクリプション商品はGoogle Playストアのみサポートします。
GamebaseRequest.Purchase.PurchasableConfiguration
API | Mandatory(M) / Optional(O) | Description |
---|---|---|
includeExpiredSubscriptions | O | 期限切れのサブスクリプション商品まで含めて照会します。 デフォルト値はfalseです。 |
API
Supported Platforms ■ UNITY_ANDROID
static void RequestSubscriptionsStatus(GamebaseRequest.Purchase.PurchasableConfiguration configuration, GamebaseCallback.GamebaseDelegate<List<GamebaseResponse.Purchase.PurchasableReceipt>> callback)
Example
public void RequestSubscriptionsStatusSample(bool includeExpiredSubscriptions)
{
var configuration = new GamebaseRequest.Purchase.PurchasableConfiguration
{
includeExpiredSubscriptions = includeExpiredSubscriptions
};
Gamebase.Purchase.RequestSubscriptionsStatus(configuration, (subscriptionStatusList, error) =>
{
if (Gamebase.IsSuccess(error) == true)
{
Debug.Log("RequestSubscriptionsStatus succeeded");
foreach (GamebaseResponse.Purchase.PurchasableSubscriptionStatus subscriptionStatus in subscriptionStatusList)
{
var message = new StringBuilder();
message.AppendLine(string.Format("storeCode:{0}", subscriptionStatus.storeCode));
message.AppendLine(string.Format("itemSeq:{0}", subscriptionStatus.itemSeq));
message.AppendLine(string.Format("price:{0}", subscriptionStatus.price));
// Subscription status
// Refer to the following document for the entire status code.
// https://docs.nhncloud.com/en/TOAST/en/toast-sdk/iap-unity/#iapsubscriptionstatusstatus
message.AppendLine(string.Format("statusCode:{0}", subscriptionStatus.statusCode));
message.AppendLine(string.Format("gamebaseProductId:{0}", subscriptionStatus.gamebaseProductId));
Debug.Log(message);
}
}
else
{
// Check the error code and handle the error appropriately.
Debug.Log(string.Format("RequestSubscriptionsStatus failed. error is {0}", error));
}
});
}
VO
public class PurchasableSubscriptionStatus
{
/// <summary>
/// アプリがインストールされたストアに対してGamebaseで内部的に定義したコードです。
/// </summary>
public string storeCode;
/// <summary>
/// ストアの決済識別子です。
/// </summary>
public string paymentId;
/// <summary>
/// サブスクリプション商品は更新されるたびにpaymentIdが変更されます。
/// このフィールドはサブスクリプション商品を初めて決済したときのpaymentIdを示します。
/// ストアや決済サーバーの状態によっては値が存在しない場合があるため
/// 常に有効な値を保障するわけではありません。
/// </summary>
public string originalPaymentId;
/// 決済識別子です。
/// purchaseTokenと一緒に「Consume」サーバーAPIを呼び出すために使用する重要な情報です。
///
/// 注意:Consume APIはゲームサーバーで呼び出してください!
/// <para/><see href="https://docs.toast.com/en/Game/Gamebase/en/api-guide/#purchase-iap">Consume API</see>
public string paymentSeq;
/// <summary>
/// 購入した商品の商品IDです。
/// </summary>
public string marketItemId;
/// <summary>
/// IAP Webコンソールの項目固有識別子
/// </summary>
public long itemSeq;
/// <summary>
/// 次の値のいずれかを持ちます。
/// * UNKNOWN:不明なタイプです。 Gamebase SDKをアップデートするか、Gamebaseサポートにお問い合わせください。
/// * CONSUMABLE:消耗品です。
/// * AUTO_RENEWABLE:サブスクリプション商品です。
/// </summary>
public string productType;
/// <summary>
/// 商品を購入したユーザーIDです。
/// 商品の購入に使用していないユーザーIDでログインすると購入した商品を受け取れません。
/// </summary>
public string userId;
/// <summary>
/// 商品の価格です。
/// </summary>
public float price;
/// <summary>
/// 通貨情報です。
/// </summary>
public string currency;
/// <summary>
/// Payment識別子。
/// paymentSeqで「Consume」サーバーAPIを呼び出すために使用される重要な情報です。
/// Consume APIで引数名を「accessToken」に指定すると渡されます。
///
/// <para/><see href="https://docs.toast.com/ko/Game/Gamebase/ko/api-guide/#purchase-iap">Purchase IAP</see>
/// </summary>
public string purchaseToken;
/// <summary>
/// この値はGoogleで購入する時に使用され、次の値を持つことができます。
/// ただし、GoogleサーバーのエラーによりGamebase決済サーバーで一時的に認証ロジックが無効になっている場合、
/// nullが返されるため常に有効な値を保障するわけではありません。
/// * null:正常決済
/// * テスト:テスト決済
/// * プロモーション:プロモーション決済
/// </summary>
public string purchaseType;
/// <summary>
/// 商品を購入した時間。(epoch time)
/// </summary>
public long purchaseTime;
/// <summary>
/// 購読の期限が切れる時間。(epoch time)
/// </summary>
public long expiryTime;
/// <summary>
/// Gamebase.Purchase.requestPurchase API呼び出し時にペイロードに渡される値です。
///
/// ストアサーバー状態によって情報が流出する場合があるため、使用を推奨しません。
/// </summary>
public string payload;
/// <summary>
/// 購読状態
/// 全体ステータスコードは次の文書を参照してください。
/// <para/><see href="https://docs.nhncloud.com/en/TOAST/en/toast-sdk/iap-unity/#iapsubscriptionstatus">IAP Subscription Status</see>
/// </summary>
public int statusCode;
/// <summary>
/// 購読状態の説明です。
/// </summary>
public string statusDescription;
/// <summary>
/// Gamebaseコンソールに登録された商品IDです。
/// Gamebase.Purchase.requestPurchase APIで商品を購入する時に使用されます。
/// </summary>
public string gamebaseProductId;
}
プロモーション決済が完了すると、GamebaseEventHandlerを通してイベントを取得して処理できます。 GamebaseEventHandlerでプロモーション決済イベントを処理する方法は、下記のガイドを参照してください。 Game > Gamebase > Unity SDK使用ガイド > ETC > Gamebase Event Handler
Supported Platforms ■ UNITY_IOS ■ UNITY_ANDROID
[注意]
iOSプロモーション決済を行うには、必ず下記のガイドに沿って設定してください。 Game > Gamebase > iOS SDK使用ガイド > 決済 > Event by Promotion
Error | Error Code | Description |
---|---|---|
PURCHASE_NOT_INITIALIZED | 4001 | Purchaseモジュールが初期化されていません。 gamebase-adapter-purchase-IAPモジュールをプロジェクトに追加したか確認してください。 |
PURCHASE_USER_CANCELED | 4002 | ゲームユーザーがアイテムの購入をキャンセルしました。 |
PURCHASE_NOT_FINISHED_PREVIOUS_PURCHASING | 4003 | 購入ロジックが完了していない状態でAPIが呼び出されました。 |
PURCHASE_NOT_ENOUGH_CASH | 4004 | 該当するストアのcashが足りないため決済することができません。 |
PURCHASE_INACTIVE_PRODUCT_ID | 4005 | 該当商品が有効な状態ではありません。 |
PURCHASE_NOT_EXIST_PRODUCT_ID | 4006 | 存在しないGamebaseProductIDで決済をリクエストしました。 |
PURCHASE_LIMIT_EXCEEDED | 4007 | 月の購入限度を超過しました。 |
PURCHASE_NOT_SUPPORTED_MARKET | 4010 | このストアには対応しておりません。 選択可能なストアは、GG(Google)、TS(ONE store)、GALAXY、AMAZON、HUAWEI、MYCARDです。 |
PURCHASE_EXTERNAL_LIBRARY_ERROR | 4201 | NHN Cloud IAPライブラリエラーです。 詳細エラーを確認してください。 |
PURCHASE_UNKNOWN_ERROR | 4999 | 定義されていない購入エラーです。 ログ全体をカスタマーセンターにアップロードしてください。なるべく早くお答えいたします。 |
PURCHASE_EXTERNAL_LIBRARY_ERROR
GamebaseError gamebaseError = error; // GamebaseError object via callback
if (Gamebase.IsSuccess(gamebaseError))
{
// succeeded
}
else
{
Debug.Log(string.Format("code:{0}, message:{1}", gamebaseError.code, gamebaseError.message));
GamebaseError moduleError = gamebaseError.error; // GamebaseError.error object from external module
if (null != moduleError)
{
int moduleErrorCode = moduleError.code;
string moduleErrorMessage = moduleError.message;
Debug.Log(string.Format("moduleErrorCode:{0}, moduleErrorMessage:{1}", moduleErrorCode, moduleErrorMessage));
}
}