ネイティブAndroid用の支払いモジュール

このセクションでは、now.gg決済モジュールを開発環境に統合する方法を説明します。

このドキュメントでは、now.ggの公式サンプルアプリやゲームをベースにした様々なコードサンプルを紹介しています。また、now.gg決済モジュールをよりよく理解し実装するために、本ドキュメント全体を通してインラインリファレンスを確認することができます。


SDKライブラリの追加

まず、決済ライブラリを含むnow.gg SDKパッケージをダウンロードし、以下の手順で開発環境に追加します:

※now.gg SDKパッケージには、決済モジュール、デモアプリ、サンプルコードが含まれています。

1. 圧縮されたnow.gg決済モジュールを展開し、パッケージ内の.aarファイルを見つけます:

 Payments.aar

2. ゲームの「build.gradle」ファイルに以下の依存関係を追加します:

dependencies {
         implementation fileTree(dir: 'libs', include: ['*.aar'])
 }


BillingClientの使用

購入ライフサイクル

now.gg決済の購入ライフサイクルフローは以下の通りです:

  • ユーザーが購入可能なプロダクトをリストアップします。
  • ユーザーがリストアップされたアプリ内プロダクトを購入するための購入フローを開始します。
  • 購入の処理:
    • 購入を確認する。
    • ユーザーにプロダクト/コンテンツを配信する。
    • プロダクトの再購入を可能にするために、購入したプロダクトを消費/配信済みとしてマークする。

用語の理解

now.gg決済は、PurchaseTokenとOrderIDを使用して、ゲームやアプリ内のプロダクトや取引を追跡します。

トークンの購入
  • PurchaseTokenは、購入者のプロダクトの所有権/権利を表します。
  • 特定のプロダクトと関連するプロダクトSKUに関連付けられています。
  • PurchaseTokenは、ユーザーによるアプリ内購入が成功した場合にのみ生成されます。
  • 1回限りの購入の場合、PurchaseTokenは取引ごとに生成されます。
  • 取引ごとに新しいPurchaseTokenが生成されます。
OrderID
  • OrderID は、now.gg課金サービスとの金融取引への参照です。
  • OrderIDは購入、払い戻し、または紛争を追跡するための参照として使用されます。
  • 固有のOrderIDは、すべての金融取引に対して作成されます。
エンタイトルメント

エンタイトルメントまたはエンタイトルメント付与という用語は、プロダクト購入後のユーザーへの「アプリ内プロダクトの引き渡し」を意味するために使用されます。

エラー処理
アプリ/ゲーム内で発生したエラーと応答は、課金応答コードを使用して分類されます。
例:SERVICE_DISCONNECTED」エラーコードは、now.gg決済サービスとゲームの接続が切断されていることを示唆しています。now.gg決済サービスとの接続を再確立するには、アプリ/ゲームを再度初期化する必要があります。

1. BillingClientの作成と初期化

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にアプリ/ゲームを追加した後にのみ使用可能になります。
  • 払い戻し処理– ご注文の払い戻し手続きは、こちらの手順に従って行ってください。
参照

2. 接続の確立

now.gg決済サービスは非同期接続プロセスを持っており、クライアントのセットアップ完了時にコールバックをキャプチャするためにBillingClientStateListenerを実装する必要があります。

  • now.gg決済サービスとの接続を確立するには、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() メソッドを呼び出してください。 
 }
});
参照


プロダクトと購入

このセクションでは、アプリ/ゲームで利用可能なアプリ内プロダクトの照会と一覧表示、および購入の処理について説明します。

このフローの手順は以下の通りです:

  1. 利用可能なプロダクトをリストアップ。
  2. 購入フローの開始。
  3. 購入の処理。

始める前に、以下のことを確認してください:

1. 利用可能なプロダクトのリストアップ

ここでの最初のステップは、利用可能なプロダクトをクエリし、ユーザーに一覧表示することです。アプリ内のプロダクト詳細のクエリを実行するには、querySkuDetailsAsync()を呼び出す必要があります。SKUの詳細をクエリすると、now.gg決済モジュールはローカライズされたプロダクト情報を返し、ユーザーに表示します。

※更新された関連するプロダクト情報が返されるため、アプリ内プロダクトをユーザーに表示する前にSKUの詳細をクエリする必要があります。

SKUTypeと注文の文字列

以下は、now.gg決済に関連する&ltSKUTypeです:

  • SkuType.SUBS – サブスクリプション
  • SkuType.INAPP – アプリ内課金
  • SkuType.ALL – アプリ内課金

querySkuDetailsAsync()を呼び出す際に、SkuDetailsParamsのインスタンスを渡すことを忘れないでください。SkuDetailsParamsは、nowStudioで設定したプロダクトIDとSKUTypeを指定します。

結果

利用可能なプロダクトをクエリした後、渡された非同期操作の結果をキャプチャするリスナーを割り当てる必要があります。

以下の例は、SkuDetailsResponseListener インターフェースの実装を示しており、onSkuDetailsResponse()をオーバーライドして、クエリの終了時にリスナーに通知できるようにします。

List<String> skuList = new ArrayList<> (); 
 skuList.add("premium_upgrade"); 
 skuList.add("gas"); 
 SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); 
 params.setSkusList(skuList).setType(SkuType.ALL); 
 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).setType(SkuType.ALL) 
    withContext(Dispatchers.IO) { 
            billingClient.querySkuDetailsAsync(params.build()) { billingResult, skuDetailsList -> 
            // Result Processing 
        } 
    } 
 }

追加情報

  • ユーザーが消耗品を再購入できるのは、最初の購入注文が完了し、プロダクトがユーザーに届けられた後です。
  • SkuDetailsオブジェクトは、アプリ内プロダクトの情報を一覧表示するために、様々なメソッドを使用して呼び出すことができます。
  • now.gg決済モジュールは、すべてのクエリ結果をSkuDetailsオブジェクトのリストに保存します。
参照


2. 購入フローの開始

購入可能なプロダクトをリストアップした後、アプリ/ゲームから購入フローを開始する必要があります。

購入フローを開始するには、アプリのメインスレッドから launchBillingFlow()メソッドを呼び出す必要があります。

ここでは、BillingFlowParamsオブジェクトが参照のために呼び出されます。このオブジェクトには、SkuDetailsオブジェクト内に保存されている関連詳細が含まれています。SkuDetailsオブジェクトは、querySkuDetailsAsync()を呼び出すことによって取得されます。

BillingFlowParamsオブジェクトの作成

購入フローを開始するには、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をリターン・レスポンス・コードのリファレンスとして使用できます。

  • 応答コードOK (0)は、起動が成功したことを示します。
  • launchBillingFlow()の呼び出しが成功すると、システムによって購入画面が表示されます。
  • now.gg決済モジュールは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およびその他の関連情報が記載された購入のコピーは、ユーザーにもメールで送信されます。
参照:


3. 購入の処理

このセクションでは、購入の処理に焦点を当てます。購入フローを開始した後、以下の手順で購入処理を行う必要があります:

  1. 購入の検証
  2. エンタイトルメントの付与
  3. 購入の結果
  4. 未消費購入の取得

3.1 購入の検証

購入を検証することで、購入の真正性を確立することができます。不正行為を減らすためのベストプラクティスは、ユーザーにプロダクトを割り当てる前に、すべての購入を認証することです。

次の2つの方法のいずれかを使用して購入を検証することができます:

  • VerifyPurchase API の使用。
  • パブリックキーを使用する。
3.1.1 VerifyPurchase 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 になります。
 }'

重要な情報

  • verifyPurchaseAPIは、アプリのバックエンドサーバーから呼び出す必要があります。
  • 購入が成功すると、PurchaseTokenが返されます。詳細については、以下の参考ドキュメントを参照してください:

3.1.2 パブリックキーの使用

購入を検証する 2 番目の方法は、パブリックキーの使用です。パブリックキーを使用して購入を検証する実装は、デモのbillingManager.javaに示されています。

  • billingManager.javaを開きます。
  • verifyValidSignature関数の場所を確認し、次にverifyPurchaseの場所を確認します。

デモの billingManager.javaにある上記の関数を使用した実装を参照することで、アプリに購入検証を実装できます。

注意:

  • こちらに記載されている手順に従って、パブリックキーを生成することができます。
  • アプリにバックエンドサーバーがある場合は、バックエンドサーバーで購入を検証することをお勧めします。
  • ユーザーにプロダクトのエンタイトルメントを付与する前に、すべての購入を検証することをお勧めします。

3.2 エンタイトルメントの付与

購入を確認した後、アプリは購入した商品の権利をユーザーに付与し、その商品を消費済み(消耗品の場合)または承認済み(サブスクリプションの場合)としてマークすることができます。
以下の方法は、ユーザーに購入権利を割り当てる方法を示しています:

3.2.1 消耗品

購入を消費するために使用できる2つの方法を提供しています:

3.2.2 サブスクリプション

購入を承認するために使用できる2つの方法を提供しています:


3.2.1 消耗型プロダクト

購入したプロダクトを消費するための2つの方法を提供しています:

A. consumeAsync を使用する

注意: バックエンドサーバを使用しないクライアントのみのアプリの場合は、このメソッドを使用する必要があります。

エンタイトルメントを付与するには、consumeAsync()メソッドを呼び出します。このメソッドは、ユーザーにプロダクトのエンタイトルメントを付与し、ユーザーに消費/配信されると、プロダクトを再購入できるようにします。

consumeAsync()の使用:

  • consumeAsync()にPurchaseTokenを含めると、購入したプロダクトのステータスが消費済みに更新され、now.gg課金サービスが再購入できるようになります。
  • 消費操作の結果を更新するには、ConsumeResponseListenerインターフェースを実装するオブジェクトを渡す必要があります。
  • 消費操作が完了すると、now.gg課金サービスは onConsumeResponse()を呼び出します。

重要な情報:

  • 購入トークンを使用して、同じ購入に対する複数の権利付与をチェックする必要があります。
  • これは、消費リクエストが失敗し、ConsumeResponseListenerインターフェースを更新するオブジェクトが更新されない場合に発生する可能性があります。
  • 購入日から3日以内に権利が付与されない場合、取引はキャンセルされ、ユーザーに返金が開始されます。

次のコード・スニペットは、購入検証と消費操作を示しています:

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.
        }
    })
}
参照:

B. consumePurchase API を使用する

consumePurchase APIは、バックエンドサーバを持つアプリのサーバサイドでの購入消費に使用する必要があります。

購入を確認した後、アプリは購入した商品の権利をユーザに付与し、商品を消費済みとして処理することができます。

消費購入には以下が含まれます。:

  • 購入した製品をユーザに割り当てます。
  • 商品が消費されたことをnow.ggに通知します。

消費購入コードのサンプル

以下のサンプルコードは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を呼び出す前にユーザーに割り当ててください。
  • API KeyPayment API Key はnowStudioのクレデンシャルセクションで確認することができます。 詳細はこちら
  • 購入が成功すると、PurchaseTokenが返されます。詳細については、以下の参考ドキュメントを参照してください:


3.2.2 サブスクリプション

重要な情報

  • 購読の購入を承認することは、ユーザーに購入権限を付与する重要なステップです。
  • 購読期間は承認の日付から開始されます。
  • 購入が購入日から3日以内に承認されない場合、購入はキャンセルされ、支払いはユーザーに返金されます。

購入を承認するために使用できる2つのメソッドを提供しました:

A. クライアント側 – 使用 acknowledgePurchase
以下のフローは、クライアント側で購入アイテムを承認するために使用されます。

注意: バックエンドサーバーを持たないクライアント専用のアプリの場合、この方法を使用する必要があります。

方法:

  • acknowledgePurchase() メソッドを呼び出します。
    • このメソッドにより、製品の権利がユーザーに付与され、承認後は再購入可能な状態になります。
  • acknowledgePurchase() に購入トークンを含めてacknowledgePurchase() を呼び出し、購入した製品のステータスを acknowledged に更新します。これにより、now.ggの課金サービスが再購入可能にします。
  • 承認操作の結果を更新するには、AcknowledgePurchaseResponseListener インタフェースを実装したオブジェクトを渡す必要があります。
  • 承認操作が完了すると、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)
}
References:

B. サーバー側 – 使用 acknowledgePurchase API

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)

参照:

重要な情報

  • API KeyPayment API Key はnowStudioのクレデンシャルセクションで確認することができます。 詳細はこちら
  • 購入が成功すると、PurchaseTokenが返されます。詳細については、以下の参考ドキュメントを参照してください:


3.3 購入結果

PurchasesUpdatedListenerは購入結果を提供します。しかし、シナリオによっては、アプリ/ゲームはユーザーが行った成功済みの購入の全てで更新されない場合があります。

これらのシナリオには、以下のようなものがあります:

  • 複数のデバイス
    このシナリオでは、ユーザーが1つのデバイスでプロダクトを購入し、購入したプロダクトが更新されていない別のデバイスで使用したい場合です。
  • 接続/ネットワーク損失
    接続/ネットワークの損失により、アプリ/ゲームは PurchasesUpdatedListenerから正常な購入通知を受信できない場合があります。
  • アプリ外での購入
    このシナリオでは、アプリ/ゲームの外で行われた購入は、ユーザーが使用できるように処理する必要があります。

上記のシナリオに関連する購入を正常に処理する方法:

  • onResume()メソッドとonCreate()メソッドで、アプリがBillingClient.queryPurchasesAsync(SkuType.ALL)を呼び出すことを確認してください。


4. 未消費の購入の処理

以下のセクションでは、未消費のアプリ内購入およびサブスクリプションを確認し、割り当てるプロセスを説明します。

以下のように、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() メソッドを使用して、未消費の購入分をクエリし、ユーザの以前のゲームセッションで未消費の購入分が適切にそのユーザに割り当てられるようにする必要があります。
    • これは、購入直後にアプリがクラッシュした場合や、購入プロセス中にインターネット接続が切断された場合に特に有効です。
  • 詳細については、接続の確立セクションを参照してください。

5. Subscription Status Callback API

(開発者提供)

このセクションでは、SubscriptionStatusCallback API を提供し、サブスクリプションの状態更新に関する通知を送信するための API 仕様を示しています。

以下は関連するワークフローです:

  • nowStudio はこのAPIを使用して、リクエストデータをゲームのバックエンドに送信します。
  • ゲームのバックエンドは、当社から提供されたAPIキー(Webhook APIキー)を使用してリクエストを認証できます。
  • サブスクリプションの現在のステータスに基づいて、ユーザーに購入権を割り当てることができます。 (こちらで定義されています)。
  • 提供されたコールバックURLを使用してリクエストデータを送信した後、当社のAPIからの応答を待ちます。
    • 成功ステータスが true の200のレスポンスが得られない場合、一定時間リトライを続けます。

注意: Subscription Status Callback API.



重要な情報

×

目次

ネイティブAndroid用の支払いモジュール

目次

ドキュメント改訂版 1.0

テキストがクリップボードにコピーされました。
copyLinkText
ご不明な点がございましたら、お気軽にお問い合わせください。 dev-support@now.gg