このセクションでは、now.gg決済モジュールを開発環境に統合する方法を説明します。
このドキュメントでは、now.ggの公式サンプルアプリやゲームをベースにした様々なコードサンプルを紹介しています。また、now.gg決済モジュールをよりよく理解し実装するために、本ドキュメント全体を通してインラインリファレンスを確認することができます。
1. 圧縮されたnow.gg決済モジュールを展開し、パッケージ内の.aarファイルを見つけます:
payments.aar
2. ゲームの「build.gradle」ファイルに以下の依存関係を追加します:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.aar'])
}
now.gg決済の購入ライフサイクルフローは以下の通りです:
now.gg決済は、PurchaseTokenとOrderIDを使用して、ゲームやアプリ内のプロダクトや取引を追跡します。
エンタイトルメントまたはエンタイトルメント付与という用語は、プロダクト購入後のユーザーへの「アプリ内プロダクトの引き渡し」を意味するために使用されます。
SERVICE_DISCONNECTED」エラーコードは、now.gg決済サービスとゲームの接続が切断されていることを示唆しています。now.gg決済サービスとの接続を再確立するには、アプリ/ゲームを再度初期化する必要があります。now.gg Paymentsを初期化する前に、必ずnow.gg IAPが利用可能かどうかを確認してください。now.gg IAPが利用できない場合にのみ、他のIAPサービスを初期化してください。
if (!BillingClient.checkIAPAvailability(activity)) {
// now.gg iapが利用できません
return;
}
BillingClientインターフェースは、now.gg決済モジュールと自身のアプリ/ゲーム間の主要な通信メカニズムとして機能します。一般的な課金操作のための同期および非同期メソッドを提供します。
BillingClient Creation --> Use newBuilder() Setup Updates of Purchase --> Call setListener() Receive updates throughout app/game --> PurchasesUpdatedListener Set PAYMENT_ID for billing --> use setAppId(PAYMENT_ID) Query unconsumed purchases after initialization --> use queryPurchasesAsync()
以下のサンプルは、BillingClient を作成および初期化する方法を示しています:
private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
@Override
public void onPurchasesUpdated(int billingResult, List<Purchase> purchases) {
if (billingResult == BillingResponse.OK) {
if (purchases == null) {
return;
}
for (Purchase purchase: purchases) {
String payload = purchase.getDeveloperPayload(); // 開発者ペイロードを取得する
// ここで購入成功を処理する
}
} else if (billingResult == BillingResponse.USER_CANCELED) {
Log.i(TAG, "onPurchasesUpdated() - user cancelled the purchase flow - skipping");
} else {
Log.w(TAG, "onPurchasesUpdated() got unknown billingResult: " + billingResult);
}
}
};
private BillingClient billingClient = BillingClient.newBuilder(activity)
.setListener(purchasesUpdatedListener)
.setAppId(PAYMENT_ID)
.build();
private val purchasesUpdatedListener = object : PurchasesUpdatedListener {
override fun onPurchasesUpdated(billingResult: Int, purchases: List<Purchase>?) {
if (billingResult == BillingResponse.OK) {
if (purchases == null) {
return
}
for (purchase in purchases) {
val payload = purchase.developerPayload // 開発者ペイロードを取得する
// ここで購入成功を処理する
}
} else if (billingResult == BillingResponse.USER_CANCELED) {
Log.i(TAG, "onPurchasesUpdated() - user cancelled the purchase flow - skipping")
} else {
Log.w(TAG, "onPurchasesUpdated() got unknown billingResult: $billingResult")
}
}
}
private val billingClient = BillingClient.newBuilder(activity)
.setListener(purchasesUpdatedListener)
.setAppId(PAYMENT_ID)
.build()
PAYMENT_IDはアプリの固有の識別子です。
PAYMENT_IDはnowStudioのアプリ詳細セクションで確認することができます。 – 詳細はこちらPAYMENT_IDは、nowStudioにアプリ/ゲームを追加した後にのみ使用可能になります。now.gg決済サービスは非同期接続プロセスを持っており、クライアントのセットアップ完了時にコールバックをキャプチャするためにBillingClientStateListenerを実装する必要があります。
startConnection()を呼び出す必要があります。startConnection()を一度だけ呼び出すようにしてください。queryPurchasesAsync() メソッドを使用して、未消費の購入分をクエリし、ユーザの以前のゲームセッションで未消費の購入分が適切にそのユーザに割り当てられるようにする必要があります。
※独自のリトライロジックを書くこともできますが、当社ではリトライロジックも提供していますので、そちらを実装することも可能です。
例
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(int billingResult) {
if (billingResult == 0) {
// BillingClientの準備ができました。ここで購入をクエリできます。
QueryPurchasesParams params = QueryPurchasesParams.newBuilder().setProductType(BillingClient.SkuType.ALL).build();
billingClient.queryPurchasesAsync(params, new PurchasesResponseListener() {
@Override
public void onQueryPurchasesResponse(BillingResult billingResult, List < Purchase > list) {
// 購入したアイテムをユーザーに割り当て、消費/確認を呼び出してください。
}
});
}
}
@Override
public void onBillingServiceDisconnected() {
// 次のリクエストで支払いモジュールへの接続を再起動するには、startConnection() メソッドを呼び出してください。
}
});
billingClient.startConnection(object: BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: int) {
if (billingResult == 0) {
// BillingClientの準備ができました。ここで購入をクエリできます。
val params = QueryPurchasesParams.newBuilder()
.setProductType(BillingClient.SkuType.ALL)
.build()
billingClient.queryPurchasesAsync(params, object: PurchasesResponseListener {
override fun onQueryPurchasesResponse(billingResult: BillingResult, list: List) {
// 購入したアイテムをユーザーに割り当て、消費/確認を呼び出してください。
}
})
}
}
override fun onBillingServiceDisconnected() {
// 次のリクエストで支払いモジュールへの接続を再起動するには、startConnection() メソッドを呼び出してください。
}
});
このセクションでは、アプリ/ゲームで利用可能なアプリ内プロダクトの照会と一覧表示、および購入の処理について説明します。
このフローの手順は以下の通りです:
始める前に、以下のことを確認してください:
ここでの最初のステップは、利用可能なプロダクトをクエリし、ユーザーに一覧表示することです。アプリ内のプロダクト詳細のクエリを実行するには、querySkuDetailsAsync()を呼び出す必要があります。SKUの詳細をクエリすると、now.gg決済モジュールはローカライズされたプロダクト情報を返し、ユーザーに表示します。
querySkuDetailsAsync() を呼び出す際には、nowStudio で設定した商品 ID を含む SkuDetailsParams のインスタンスを渡す必要があります。結果
以下の例は、SkuDetailsResponseListener インターフェースの実装を示しており、onSkuDetailsResponse()をオーバーライドして、クエリの終了時にリスナーに通知できるようにします。
List<String> skuList = new ArrayList<> ();
skuList.add("premium_upgrade");
skuList.add("gas");
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList);
billingClient.querySkuDetailsAsync(params.build(),
new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(int billingResult,
List<SkuDetails> skuDetailsList) {
// Process the result.
}
});
fun querySkuDetails() {
val skuList = ArrayList<String>()
skuList.add("premium_upgrade")
skuList.add("gas")
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList)
withContext(Dispatchers.IO) {
billingClient.querySkuDetailsAsync(params.build()) { billingResult, skuDetailsList ->
// Result Processing
}
}
}
SkuDetailsオブジェクトは、アプリ内プロダクトの情報を一覧表示するために、様々なメソッドを使用して呼び出すことができます。SkuDetailsオブジェクトのリストに保存します。購入可能なプロダクトをリストアップした後、アプリ/ゲームから購入フローを開始する必要があります。
購入フローを開始するには、アプリのメインスレッドから launchBillingFlow()メソッドを呼び出す必要があります。
ここでは、BillingFlowParamsオブジェクトが参照のために呼び出されます。このオブジェクトには、SkuDetailsオブジェクト内に保存されている関連詳細が含まれています。SkuDetailsオブジェクトは、querySkuDetailsAsync()を呼び出すことによって取得されます。
購入フローを開始するには、BillingFlowParams.Builderクラスを使用してBillingFlowParamsオブジェクトを作成する必要があります。以下のコード・スニペットを参考にしてください:
// An activity reference for billing flow initiation
Activity activity = ...;
// Call querySkuDetailsAsync() to retrieve a value for 'skuDetails'.
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.setDeveloperPayload("任意の開発者ペイロード")
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);
//Result
// An activity reference for billing flow initiation
val activity : Activity = ...;
// Call querySkuDetailsAsync() to retrive a value for 'skuDetails'.
val flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.setDeveloperPayload("任意の開発者ペイロード")
.build()
billingClient.launchBillingFlow(activity, flowParams)
//Result
BillingClient.BillingResponseをリターン・レスポンス・コードのリファレンスとして使用できます。
0)は、起動が成功したことを示します。launchBillingFlow()の呼び出しが成功すると、システムによって購入画面が表示されます。onPurchasesUpdated()を呼び出して、PurchasesUpdatedListenerインターフェースを実装するリスナーに購入結果を伝えます。setListener()メソッドを使用してBillingClientを初期化する際に指定します。次の例は、onPurchasesUpdated()メソッドをオーバーライドするプロセスの概要です:
@Override
void onPurchasesUpdated(int billingResult, List<Purchase>) {
if (billingResult == 0 && purchases != null) {
for (Purchase purchase : purchases) {
String payload = purchase.getDeveloperPayload(); // get developer payload
handlePurchase(purchase);
}
} else if (billingResult == 1) {
// エラーハンドリング - ユーザーが購入フローを終了したことによる原因
} else {
// エラーハンドリング - その他の原因(エラーコードに基づく)
}
}
override fun onPurchasesUpdated(billingResult: int, purchases: List<Purchase>?) {
if (billingResult == 0 && purchases != null) {
for (purchase in purchases) {
val payload: String = purchase.developerPayload // get developer payload
handlePurchase(purchase)
}
} else if (billingResult == 1) {
// エラーハンドリング - ユーザーが購入フローを終了したことによる原因
} else {
// エラーハンドリング - その他の原因(エラーコードに基づく)
}
}
※PurchasesUpdated()メソッドは、可能性のあるレスポンス・コードを処理するために実装する必要があります。
PurchaseTokenが生成されます。
PurchaseTokenは、アプリ内で購入したプロダクトと、購入した対応するユーザーを表す固有の識別子でもあります。OrderIDは、その後の注文ごとに生成され、now.gg決済サービスとの紛争や払い戻しのリファレンスに使用することができます。OrderIDおよびその他の関連情報が記載された購入のコピーは、ユーザーにもメールで送信されます。このセクションでは、購入の処理に焦点を当てます。購入フローを開始した後、以下の手順で購入処理を行う必要があります:
購入は verifyPurchase 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>"
}
response = requests.post(url, headers=headers, data=data)
print("レスポンスステータスコード:", response.status_code)
print("レスポンスボディ:", response.text)
curl -X \ POST "https://payments-api.now.gg/v2/sellers/order/verifyPurchase" \ -H \ "Authorization: <payment_api_key_here>" \ -H \ "Content-Type: application/x-www-form-urlencoded" \ -d "purchaseToken=<purchase_token_here>"
購入を確認した後、アプリは購入した商品の権利をユーザーに付与し、その商品を消費済み(消耗品の場合)または承認済み(サブスクリプションの場合)としてマークすることができます。
以下の方法は、ユーザーに購入権利を割り当てる方法を示しています:
購入を消費するために使用できる2つの方法を提供しています:
購入を承認するために使用できる2つの方法を提供しています:
購入したプロダクトを消費するための2つの方法を提供しています:
注意: バックエンドサーバを使用しないクライアントのみのアプリの場合は、このメソッドを使用する必要があります。
エンタイトルメントを付与するには、consumeAsync()メソッドを呼び出します。このメソッドは、ユーザーにプロダクトのエンタイトルメントを付与し、ユーザーに消費/配信されると、プロダクトを再購入できるようにします。
consumeAsync()の使用:
ConsumeResponseListenerインターフェースを実装するオブジェクトを渡す必要があります。onConsumeResponse()を呼び出します。queryPurchasesAsync() を呼び出して、未消費の購入を確認することをお勧めします。こちらを参照してください。ConsumeResponseListenerインターフェースを更新するオブジェクトが更新されない場合に発生する可能性があります。次のコード・スニペットは、購入検証と消費操作を示しています:
void handlePurchase(Purchase purchase) {
// Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
Purchase purchase = ...;
// Verify the purchase.
// Ensure entitlement was not already granted for this purchaseToken.
// Grant the entitlement to the user.
ConsumeResponseListener listener = new ConsumeResponseListener() {
@Override
public void onConsumeResponse(int billingResult, String purchaseToken) {
if (billingResult == 0) {
// Handle the success of the consume operation.
}
}
};
billingClient.consumeAsync(purchase.getPurchaseToken(), listener);
}
fun handlePurchase(purchase: Purchase) {
// Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
val purchase: Purchase = ...;
// Verify the purchase.
// Ensure entitlement was not already granted for this purchaseToken.
// Grant the entitlement to the user.
billingClient.consumeAsync(purchase.getPurchaseToken(), {
billingResult,
outToken - >
if (billingResult == 0) {
// Handle the success of the consume operation.
}
})
}
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>",
"developerPayload": "developerPayload" // オプション
}
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>",
"developerPayload" : "developerPayload" // オプション
注意:
購入を承認するために使用できる2つのメソッドを提供しました:
注意: バックエンドサーバーを持たないクライアント専用のアプリの場合、この方法を使用する必要があります。
方法:
acknowledgePurchase() メソッドを呼び出します。
acknowledgePurchase() に購入トークンを含めてacknowledgePurchase() を呼び出し、購入した製品のステータスを acknowledged に更新します。これにより、now.ggの課金サービスが再購入可能にします。onAcknowledgePurchaseResponse() を呼び出します。このメソッドはオーバーライド可能です。重要な情報:
AcknowledgePurchaseResponseListener インタフェースを更新しない場合、このような状況が発生する可能性があります。以下のコードスニペットは、購入の検証と承認操作を示しています:
void handlePurchase(Purchase purchase) {
// Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
Purchase purchase = ...;
// Verify the purchase.
// Ensure entitlement was not already granted for this purchaseToken.
// Grant the entitlement to the user.
// Acknowledge Subscription
final AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = new AcknowledgePurchaseResponseListener() {
@Override
public void onAcknowledgePurchaseResponse(@BillingResponse int responseCode) {
if (responseCode == 0) {
// Handle the success of the acknowledgement operation.
}
}
};
AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchaseToken)
.build();
BillingClient.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
}
fun handlePurchase(purchase: Purchase) {
// Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
val purchase: Purchase = ...;
// Verify the purchase.
// Ensure entitlement was not already granted for this purchaseToken.
// Grant the entitlement to the user.
// Acknowledge Subscription
val acknowledgePurchaseResponseListener = object : AcknowledgePurchaseResponseListener {
override fun onAcknowledgePurchaseResponse(@BillingResponse responseCode: Int) {
if (responseCode == 0) {
// Handle the success of the acknowledgement operation.
}
}
val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchaseToken)
.build()
BillingClient.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener)
}
acknowledgePurchase API は、バックエンドサーバーを持つアプリのためのサーバーサイド購入承認に使用する必要があります。
購入を確認した後、承認済みとしてマークする必要があります。
以下のサンプルコードは、acknowledgePurchase API を使用した関連するリクエストを示しています。
import requests
url = "https://payments-api.now.gg/v2/seller/order/acknowledgepurchase"
payload = 'purchaseToken=<purchase_token_here>'
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)
参照:
Payment API Key はnowStudioのクレデンシャルセクションで確認することができます。 詳細はこちらPurchasesUpdatedListenerは購入結果を提供します。しかし、シナリオによっては、アプリ/ゲームはユーザーが行った成功済みの購入の全てで更新されない場合があります。
これらのシナリオには、以下のようなものがあります:
PurchasesUpdatedListenerから正常な購入通知を受信できない場合があります。上記のシナリオに関連する購入を正常に処理する方法:
onResume()メソッドとonCreate()メソッドで、アプリがBillingClient.queryPurchasesAsync(SkuType.ALL)を呼び出すことを確認してください。以下のセクションでは、未消費のアプリ内購入およびサブスクリプションを確認し、割り当てるプロセスを説明します。
以下のように、queryPurchasesAsyncメソッドを使用すると、ユーザーの未消費購入リストを返すことができます:
QueryPurchasesParams params = QueryPurchasesParams.newBuilder().setProductType(BillingClient.SkuType.ALL).build();
billingClient.queryPurchasesAsync(params, new PurchasesResponseListener() {
@Override
public void onQueryPurchasesResponse(BillingResult billingResult, List < Purchase > list) {
// 購入したアイテムをユーザーに割り当て、消費/確認を呼び出してください。
}
});
val params = QueryPurchasesParams.newBuilder()
.setProductType(BillingClient.SkuType.ALL)
.build()
billingClient.queryPurchasesAsync(params, object : PurchasesResponseListener {
override fun onQueryPurchasesResponse(billingResult: BillingResult, list: List) {
// 購入したアイテムをユーザーに割り当て、消費/確認を呼び出してください。
}
})
queryPurchasesAsync() メソッドを使用して、未消費の購入分をクエリし、ユーザの以前のゲームセッションで未消費の購入分が適切にそのユーザに割り当てられるようにする必要があります。
このセクションでは、SubscriptionStatusCallback API を提供し、サブスクリプションの状態更新に関する通知を送信するための API 仕様を示しています。
以下は関連するワークフローです:
ドキュメント改訂版 1.0