ここではアプリでアプリ内決済機能を使用するために必要な設定方法についてご案内いたします。
Gamebaseは、一つの統合された決済APIを提供することで、ゲームで簡単に各ストアのアプリ内決済を連動することができるようサポートします。
[注意]
ONE Storeはv17, v19, v21をサポートします。 ONE Storeはバージョンごとにv17、v19、v21、externalのいずれか1つのみ使用することができ、同時に使用できません。
String STORE_CODE = "GG"; // Google
GamebaseConfiguration configuration = GamebaseConfiguration.newBuilder(APP_ID, APP_VERSION, STORE_CODE)
.build();
Gamebase.initialize(activity, configuration, callback);
アイテムの購入は大きく分けて決済フロー、消費フロー、再処理フローの3つがあります。 決済フローは、次のような順序で実装してください。
未消費決済履歴リストに値がある場合、次のような順序でConsume Flowを進行してください。
[注意]
アイテムの重複支給が発生しないように、ゲームサーバーで必ず重複支給の有無をチェックしてください。
購入するアイテムのgamebaseProductIdを利用して次のAPIを呼び出し、購入をリクエストします。
gamebaseProductIdは一般的にはストアに登録したアイテムのIDと同じですが、Gamebaseコンソールで変更することもできます。
ゲームユーザーが購入をキャンセルすると、GamebaseError.PURCHASE_USER_CANCELEDエラーが返ります。
キャンセル処理をしてください。
API
+ (void)Gamebase.Purchase.requestPurchase(@NonNull final Activity activity,
@NonNull final String gamebaseProductId,
@NonNull final GamebaseDataCallback<PurchasableReceipt> callback);
Example
Gamebase.Purchase.requestPurchase(activity, gamebaseProductId, new GamebaseDataCallback<PurchasableReceipt>() {
@Override
public void onCallback(PurchasableReceipt receipt, GamebaseException exception) {
if (Gamebase.isSuccess(exception)) {
// Succeeded.
} else if(exception.getCode() == GamebaseError.PURCHASE_USER_CANCELED) {
// User canceled.
} else {
// To Purchase Item Failed cause of the error
}
}
});
VO
class PurchasableReceipt {
// 購入したアイテムの商品IDです。
@Nullable
String gamebaseProductId;
// Gamebase.Purchase.requestPurchase API呼び出し時にpayloadに渡された値です。
// ストアサーバーの状態によっては情報が失われる場合があるため、使用を推奨しません。
@Nullable
String payload;
// 購入した商品の価格です。
float price;
// 通貨コードです。
@NonNull
String currency;
// 決済識別子です。
// purchaseTokenと一緒にConsumeサーバーAPIを呼び出すのに使用する重要な情報です。
//
// Consume API : https://docs.toast.com/en/Game/Gamebase/en/api-guide/#purchase-iap
// 注意:Consume APIは、ゲームサーバーで呼び出してください!
@NonNull
String paymentSeq;
// 決済識別子です。
// paymentSeqと一緒にConsumeサーバーAPIを呼び出すのに使用する重要な情報です。
// Consume APIでは「accessToken」という名前のパラメータで渡す必要があります。
//
// Consume API : https://docs.toast.com/en/Game/Gamebase/en/api-guide/#purchase-iap
// 注意:Consume APIは、ゲームサーバーで呼び出してください!
@Nullable
String purchaseToken;
// Google、Appleのようにストアコンソールに登録された商品IDです。
@NonNull
String marketItemId;
// 商品タイプです。次の値を使用できます。
// * UNKNOWN:認識できないタイプ。Gamebase SDKをアップデートするか、Gamebaseサポートへお問い合わせください。
// * CONSUMABLE:消費性商品。
// * AUTO_RENEWABLE:購読型商品。
// * CONSUMABLE_AUTO_RENEWABLE:購読型商品を購入したユーザーに、定期的に消費が可能な商品を支給したい場合に使われる「消費が可能な購読商品」。
@NonNull
String productType;
// 商品を購入したUser ID。
// 商品を購入していないUser IDでログインした場合、購入したアイテムを獲得できません。
@NonNull
String userId;
// ストアの決済識別子です。
@Nullable
String paymentId;
// 商品を購入した時刻です。(epoch time)
long purchaseTime;
// 購読が終了する時刻です。(epoch time)
long expiryTime;
// Google決済時に使用される値。次の値を使用できます。
// しかしGoogleサーバーで障害が発生してGamebase決済サーバーで一時的に検証ロジックをオフにする場合は
// nullを返すため、常に有効な値を保障しないことに注意してください。
// * null:一般決済
// * Test:テスト決済
// * Promo:Promotion決済
@Nullable
String purchaseType;
// 購読商品は更新されるごとにpaymentIdが変更されます。
// このフィールドは最初に購読商品を決済した時のpaymentIdを伝えます。
// ストアによっては、決済サーバーの状態に応じた値が存在しない場合があるため
// 常に有効な値を保障するわけではありません。
@Nullable
String originalPaymentId;
// itemSeqで商品を購入するLegacy API用の識別子です。
long itemSeq;
// 商品を購入したStore Code。
@NonNull
public String storeCode;
}
Response Example
{
"gamebaseProductId": "my_product_001",
"price": 1000.0,
"currency": "KRW",
"paymentSeq": "2021032510000001",
"purchaseToken": "5U_NVCLKSDFKLJJ...",
"marketItemId": "my_product_001",
"productType": "CONSUMABLE",
"userId": "AS@123456ABCDEFGHIJ",
"paymentId": "GPA.1111-2222-3333-44444",
"purchaseTime": 1616649225531,
"expiryTime": 0,
"itemSeq": 1000001
}
{
"gamebaseProductId": "my_subcription_product_001",
"price": 1000.0,
"currency": "KRW",
"paymentSeq": "2021032510000001",
"purchaseToken": "5U_NVCLKKLJLSDG...",
"marketItemId": "my_subcription_product_001",
"productType": "CONSUMABLE_AUTO_RENEWABLE",
"userId": "AS@123456ABCDEFGHIJ",
"paymentId": "GPA.1111-2222-3333-56789",
"purchaseTime": 1617069916128,
"expiryTime": 1617070323784,
"purchaseType": "Test",
"originalPaymentId": "GPA.1111-2222-3333-56789",
"itemSeq": 1000002
}
アイテムリストを照会したい場合、次のAPIを呼び出します。コールバックで返される配列(array)の中にはそれぞれ各アイテムの情報が含まれています。
API
+ (void)Gamebase.Purchase.requestItemListPurchasable(Activity activity, GamebaseDataCallback<List<PurchasableItem>> callback);
Example
Gamebase.Purchase.requestItemListPurchasable(activity, new GamebaseDataCallback<List<PurchasableItem>>() {
@Override
public void onCallback(List<PurchasableItem> data, GamebaseException exception) {
if (Gamebase.isSuccess(exception)) {
// Succeeded.
} else {
// Failed.
Log.e(TAG, "Request item list failed- "
+ "errorCode: " + exception.getCode()
+ "errorMessage: " + exception.getMessage());
}
}
});
VO
class PurchasableItem {
// Gamebaseコンソールに登録された商品IDです。
// Gamebase.Purchase.requestPurchase APIで商品を購入する時に使用されます。
@Nullable
String gamebaseProductId;
// 商品の価格です。
float price;
// 通貨コードです。
@Nullable
String currency;
// Gamebaseコンソールに登録されている商品名です。
@Nullable
String itemName;
// Google、Appleのようにストアコンソールに登録された商品IDです。
@NonNull
String marketItemId;
// 商品タイプです。次の値を使用できます。
// * UNKNOWN:認識できないタイプ。Gamebase SDKをアップデートするか、Gamebaseサポートへお問い合わせください。
// * CONSUMABLE:消費性商品。
// * AUTORENEWABLE:購読型商品。
// * CONSUMABLE_AUTO_RENEWABLE:購読型商品を購入したユーザーに定期的に消費が可能な商品を支給したい場合に使われる「消費が可能な購読商品」。
@NonNull
String productType;
// 通貨記号が含まれるローカライズされた価格情報です。
@Nullable
String localizedPrice;
// ストアコンソールに登録されているローカライズされた商品名です。
@Nullable
String localizedTitle;
// ストアコンソールに登録されているローカライズされた商品説明です。
@Nullable
String localizedDescription;
// Gamebaseコンソールで該当商品の「使用有無」を表します。
boolean isActive;
// itemSeqで商品を購入するLegacy API用の識別子です。
long itemSeq;
}
Response Example
{
"gamebaseProductId": "my_product_001",
"price": 1000.0,
"currency": "KRW",
"itemName": "Consumable product for test",
"marketItemId": "my_product_001",
"productType": "CONSUMABLE",
"localizedPrice": "₩1,000",
"localizedTitle": "TEST PRODUCT 001",
"localizedDescription": "Product for test 001",
"isActive": true,
"itemSeq": 1000001
}
PurchasableConfiguration
API | Mandatory(M) / Optional(O) | Description |
---|---|---|
newBuilder() | M | Configurationオブジェクト作成のためのBuilderを作成します。 |
build() | M | 設定を終えたBuilderをConfigurationオブジェクトに変換します。 |
setAllStores(boolean allStores) | O | 同じUserIDで他のストアにて購入した未消費履歴も変換します。 デフォルト値はfalseです。 |
API
+ (void)Gamebase.Purchase.requestItemListOfNotConsumed(@NonNull final Activity activity,
@NonNull final PurchasableConfiguration configuration,
@NonNull final GamebaseDataCallback<List<PurchasableReceipt>> callback);
Example
final PurchasableConfiguration configuration = PurchasableConfiguration.newBuilder().build();
Gamebase.Purchase.requestItemListOfNotConsumed(activity, configuration, new GamebaseDataCallback<List<PurchasableReceipt>>() {
@Override
public void onCallback(List<PurchasableReceipt> data, GamebaseException exception) {
if (Gamebase.isSuccess(exception)) {
// Succeeded.
} else {
// Failed.
Log.e(TAG, "Request item list failed- "
+ "errorCode: " + exception.getCode()
+ "errorMessage: " + exception.getMessage());
}
}
});
現在のユーザーID基準で有効になっている定期購入リストを照会します。 決済が完了した定期購入商品(自動更新型定期購入、自動更新型消費性定期購入商品)は、有効期限が切れる前まで照会できます。 購読ライフサイクル処理は、次の文書をご覧ください。 NHN Cloud > SDK使用ガイド > IAP > Android > Google Play Store購読(定期的決済)機能 > 購読ライフサイクル処理
[注意]
現在定期購入商品は、Androidの場合はGoogle Playストアのみサポートします。
PurchasableConfiguration
API | Mandatory(M) / Optional(O) | Description |
---|---|---|
newBuilder() | M | Configurationオブジェクト作成のためのBuilderを作成します。 |
build() | M | 設定を終えたBuilderをConfigurationオブジェクトに変換します。 |
setAllStores(boolean allStores) | O | 同じUserIDで他のストアにて購入した購読も変換します。 デフォルト値はfalseです。 |
API
+ (void)Gamebase.Purchase.requestActivatedPurchases(@NonNull final Activity activity,
@NonNull final PurchasableConfiguration configuration,
@NonNull final GamebaseDataCallback<List<PurchasableReceipt>> callback);
Example
final PurchasableConfiguration configuration = PurchasableConfiguration.newBuilder()
.setAllStores(true)
.build();
Gamebase.Purchase.requestActivatedPurchases(activity, configuration, new GamebaseDataCallback<List<PurchasableReceipt>>() {
@Override
public void onCallback(List<PurchasableReceipt> data, GamebaseException exception) {
if (Gamebase.isSuccess(exception)) {
// Succeeded.
} else {
// Failed.
Log.e(TAG, "Request subscription list failed- "
+ "errorCode: " + exception.getCode()
+ "errorMessage: " + exception.getMessage());
}
}
});
現在のユーザーID基準で購入した購読商品の状態を照会できます。 決済が完了した購読商品(自動更新型購読、自動更新型消費性購読商品)は、期限が切れる前まで継続して照会できます。 PurchasableConfiguration.setIncludeExpiredSubscriptions(true)APIで、有効期限が切れた購読商品の状態も照会できます。 購読ステータスコードは、次の文書を参照してください。 NHN Cloud > SDK使用ガイド > IAP > Android > NHN Cloud IAP Class Reference > IapSubscriptionStatus.StatusCode
[注意]
- 購読ステータスコードは、以下のガイドに従って購読イベント設定を行うと正常に返されます。
- Game > Gamebase > ストアコンソールガイド > Googleコンソールガイド > Googleシステム内リアルタイム購読情報イベント配信設定
- イベント設定を行っていない状態で購入した購読商品のステータスコードは常に0(PURCHASED)が返されます。
- 現在、購読商品はGoogle Playストアのみサポートします。
PurchasableConfiguration
API | Mandatory(M) / Optional(O) | Description |
---|---|---|
newBuilder() | M | Configurationオブジェクトを作成するためのBuilderを作成します。 |
build() | M | 設定を終えたBuilderをConfigurationオブジェクトに変換します。 |
setIncludeExpiredSubscriptions(boolean include) | O | 有効期限が切れた購読商品を含めます。 デフォルト値はfalseです。 |
API
+ (void)Gamebase.Purchase.requestSubscriptionsStatus(@NonNull final Activity activity,
@NonNull final PurchasableConfiguration configuration,
@NonNull final GamebaseDataCallback<List<PurchasableSubscriptionStatus>> callback);
Example
final PurchasableConfiguration configuration = PurchasableConfiguration.newBuilder()
.setIncludeExpiredSubscriptions(true)
.build();
Gamebase.Purchase.requestSubscriptionsStatus(activity, configuration, new GamebaseDataCallback<List<PurchasableSubscriptionStatus>>() {
@Override
public void onCallback(List<PurchasableSubscriptionStatus> data, GamebaseException exception) {
if (Gamebase.isSuccess(exception)) {
// Succeeded.
} else {
// Failed.
Log.e(TAG, "Request status of subscription list failed- "
+ "errorCode: " + exception.getCode()
+ "errorMessage: " + exception.getMessage()
+ "errorDetail: " + exception.toString());
}
}
});
VO
class PurchasableSubscriptionStatus {
// 購入したアイテムの商品IDです。
@Nullable
String gamebaseProductId;
// 購読ステータスコードです。
//
// IapSubscriptionStatus.StatusCode : https://docs.nhncloud.com/en/TOAST/en/toast-sdk/iap-android/#iapsubscriptionstatusstatuscode
public int statusCode;
// 購読ステータスコードの説明です。
@NonNull
public String statusDescription;
// 購入した商品の価格です。
float price;
// 通貨コードです。
@NonNull
String currency;
// 決済識別子です。
// purchaseTokenと一緒に「Consume」サーバーAPIを呼び出すために使用する重要な情報です。
//
// Consume API : https://docs.toast.com/en/Game/Gamebase/en/api-guide/#purchase-iap
// 注意: Consume APIはゲームサーバーで呼び出してください!
@NonNull
String paymentSeq;
// 決済識別子です。
// paymentSeqと一緒に「Consume」サーバーAPIを呼び出すために使用する重要な情報です。
// Consume APIでは'accessToken'という名前のパラメータで渡す必要があります。
//
// Consume API : https://docs.toast.com/en/Game/Gamebase/en/api-guide/#purchase-iap
// 注意: Consume APIは、ゲームサーバーで呼び出してください!
@NonNull
String purchaseToken;
// Google、Appleなどのストアコンソールに登録された商品IDです。
@NonNull
String marketItemId;
//商品タイプとして、次の値が来ることができます。
// * UNKNOWN:認識できないタイプ。 Gamebase SDKをアップデートするか、Gamebaseサポートにお問い合わせください。
// * CONSUMABLE:消費性商品。
// * AUTO_RENEWABLE:購読商品。
// * CONSUMABLE_AUTO_RENEWABLE:購読商品購を購入したユーザーに定期的に消費が可能な商品を支給したい場合に使用される「消費が可能な購読商品」。
@NonNull
String productType;
// 商品を購入したUser ID.
// 商品を購入していないUser IDでログインした場合は購入したアイテムを獲得できません。
@NonNull
String userId;
// 商品を購入したStore Code。
@NonNull
public String storeCode;
// ストアの決済識別子です。
@Nullable
String paymentId;
// 商品を購入した時刻です。(epoch time)
long purchaseTime;
// 購読が終了する時刻です。(epoch time)
long expiryTime;
// Google決済時に使用される値で、次の値が来ることができます。
// しかしGoogleサーバーで障害が発生してGamebase決済サーバーで一時的に検証ロジックをオフにした場合には
// nullのみ返されるため常に有効な値を保障するわけではないことに注意してください。
// * null :一般決済
// * Test :テスト決済
// * Promo : Promotion決済
@Nullable
String purchaseType;
// 購読商品は更新されるたびにpaymentIdが変更されます。
// このフィールドは、最初の購読商品を決済したときのpaymentIdを示します。
// ストアや決済サーバーの状態によっては値が存在しない場合があるため
// 常に有効な値を保障するわけではありません。
@Nullable
String originalPaymentId;
// itemSeqで商品を購入するLegacy API用の識別子です。
long itemSeq;
// Gamebase.Purchase.requestPurchase API呼び出し時にpayloadに渡した値です。
// ストアサーバーの状態によっては情報が失われる場合があるため、使用を推奨しません。
@Nullable
String payload;
}
Response Example
{
"gamebaseProductId": "my_subcription_product_002",
"statusCode": 13,
"statusDescription": "EXPIRED",
"userId": "AS@123456ABCDEFGHIJ",
"storeCode": "GG",
"currency": "KRW",
"expiryTime": 1675012345678,
"itemSeq": 1000003,
"marketItemId": "my_subcription_product_002",
"originalPaymentId": "GPA.1111-2222-3333-56789",
"paymentId": "GPA.1111-2222-3333-56789",
"paymentSeq": "2021032510000002",
"price": 1000.0,
"productType": "CONSUMABLE_AUTO_RENEWABLE",
"purchaseTime": 1675001234567,
"purchaseToken": "kfetTfGk4...",
"purchaseType": "Test"
}
プロモーション決済が完了すると、GamebaseEventHandlerを通してイベントを取得して処理できます。 GamebaseEventHandlerでプロモーション決済イベントを処理する方法は、下記のガイドを参照してください。 Game > Gamebase > Android SDK使用ガイド > ETC > Gamebase Event Handler
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_INACTIVE_PRODUCT_ID | 4005 | 該当商品が有効になっていません。 |
PURCHASE_NOT_EXIST_PRODUCT_ID | 4006 | 存在しないGamebaseProductIDで決済をリクエストしました。 |
PURCHASE_LIMIT_EXCEEDED | 4007 | 月の購入限度を超過しました。 |
PURCHASE_NOT_SUPPORTED_MARKET | 4010 | このストアには対応していません。 選択可能なストアはGG(Google)、ONESTORE、GALAXY、AMAZON、HUAWEI, MYCARDです。 |
PURCHASE_EXTERNAL_LIBRARY_ERROR | 4201 | NHN Cloud IAPライブラリエラーです。 詳細エラーを確認してください。 |
PURCHASE_UNKNOWN_ERROR | 4999 | 定義されていない購入エラーです。 ログ全体をカスタマーセンターにアップロードしてください。なるべく早くお答えいたします。 |
PURCHASE_EXTERNAL_LIBRARY_ERROR
Gamebase.Purchase.requestPurchase(activity, gamebaseProductId, new GamebaseDataCallback<PurchasableReceipt>() {
@Override
public void onCallback(PurchasableReceipt data, GamebaseException exception) {
if (Gamebase.isSuccess(exception)) {
Log.d(TAG, "Purchase successful");
...
} else {
Log.e(TAG, "Purchase failed");
// Gamebase Error Info
int errorCode = exception.getCode();
String errorMessage = exception.getMessage();
if (errorCode == GamebaseError.PURCHASE_EXTERNAL_LIBRARY_ERROR) {
// IAP Error Info
int moduleErrorCode = exception.getDetailCode();
String moduleErrorMessage = exception.getDetailMessage();
...
}
}
}
});