AIDL を通じて Google Play 請求サービスを使用する

警告: AIDL はすでにサポートが終了しており、将来のリリースで完全に削除される予定です。Google Play 請求サービス機能を実装するには、Google Play 請求サービス ライブラリを使用してください。

Android インターフェース定義言語(AIDL)インターフェースを使用して、Google Play 請求サービスの一部の機能を実装することができます。

アイテムを購入する

図 1: 購入リクエストの基本シーケンス

Google Play Billing API を使用した一般的な購入フローは次のとおりです。

  1. アプリが Google Play に isBillingSupported リクエストを送信して、使用している Google Play Billing API のバージョンがサポートされているか確認します。また、このリクエストでは、ユーザーの国内で Google Play を通じた請求がサポートされているかどうかも確認されます。
  2. アプリの起動時、またはユーザーのログイン時に、ユーザーの所有アイテムを Google Play で確認することをおすすめします。ユーザーの購入情報を照会するには、getPurchases リクエストを送信します。リクエストが成功すると、購入済みアイテムのアイテム ID のリスト、個別の購入詳細のリスト、購入に対する署名リストを含む Bundle が Google Play から返されます。
  3. 通常は、購入可能なアイテムをユーザーに知らせます。Google Play に定義しておいたアプリ内アイテムの詳細についてアプリから照会するには、getSkuDetails リクエストを送信します。この照会リクエストにはアイテム ID のリストを指定する必要があります。リクエストが成功すると、アイテムの価格、タイトル、説明、購入タイプなどの詳細情報を含む Bundle が Google Play から返されます。
  4. ユーザーが所有していないアプリ内アイテムの場合は、購入を開始できます。購入リクエストを開始するには、アプリから getBuyIntent リクエストを送信します。その際、購入するアイテムのアイテム ID や各種パラメータを指定します。Google Play Console 内で新しいアプリ内アイテムを作成した場合は、アイテム ID を記録する必要があります。
    1. 購入手続き UI を起動する際にアプリが使用する PendingIntent を含む Bundle が Google Play から返されます。
    2. アプリは startIntentSenderForResult メソッドを呼び出して、ペンディング インテントを発行します。
    3. 購入手続きフローが終了すると(つまり、ユーザーが正常にアイテムを購入した場合や、購入をキャンセルした場合)、Google Play はレスポンス IntentonActivityResult メソッドに送信します。onActivityResult の結果コードには、購入が成功したのかキャンセルされたのかを示す結果コードが格納されます。レスポンス Intent には、Google Play が購入トランザクションを一意に識別するために生成した purchaseToken 文字列などの購入アイテム情報が格納されます。また、Intent にはデベロッパーの秘密鍵で署名された購入の署名も含まれます。

Google Play Billing API の呼び出しやサーバー レスポンスの詳細については、Google Play 請求サービス リファレンスをご覧ください。

アプリ内アイテムを消費する

消費メカニズムを利用して、管理対象アイテムのユーザー所有権をトラッキングすることができます。

管理対象アイテムはすべて、Google Play Billing API 内で管理されています。つまり、管理対象アイテム購入のユーザー所有権はすべて Google Play によって管理されており、ユーザーの購入情報は、必要なときにいつでもアプリから照会できます。ユーザーが正常に管理対象アイテムを購入すると、その購入は Google Play 内で記録されます。管理対象アイテムが購入されると、「所有された」と見なされます。「所有された」状態の管理対象アイテムを、Google Play から購入することはできません。Google Play 内で再び購入可能な状態にするには、「所有された」管理対象アイテムを対象とする消費リクエストを送信する必要があります。管理対象アイテムを消費すると、「所有されていない」状態に戻り、以前の購入データは破棄されます。

図 2: 消費リクエストの基本シーケンス

ユーザーが所有しているアイテムのリストを取得するには、アプリから Google Play に getPurchases 呼び出しを送信します。アプリは、consumePurchase 呼び出しを送信することで、消費リクエストを行います。リクエストの引数には、購入時に Google Play から取得した管理対象アイテムに固有の purchaseToken 文字列を指定する必要があります。正常に消費が記録されたことを示すステータス コードが Google Play から返されます。

消費不可能な管理対象アイテムと消費可能な管理対象アイテム

管理対象アイテムの消費可否は、デベロッパーが決定することができます。

消費不可アイテム
アプリ内で一度だけ購入することが可能で、その効力がずっと続く管理対象アイテムは、通常、消費可能にはしません。このようなアイテムは一度購入が行われると、永続的にユーザーの Google アカウントに関連付けられます。消費不可にする管理対象アイテムの例としては、プレミアム アップグレードやレベルパックなどがあります。
消費可能アイテム
逆に、何度も購入可能なアイテムは、消費可能にすることができます。通常、一時的な効力を持つアイテムは、消費可能にします。たとえば、ゲーム内キャラクターがライフポイントを増やしたり、追加のゴールドコインを獲得したりするような場合が該当します。アプリ内で購入したアイテムに効力や効果を付与することを、管理対象アイテムを「プロビジョニング」すると言います。ユーザーに対する管理対象アイテムのプロビジョニング方法を管理し、トラッキングするのは、デベロッパーの作業です。

重要: 消費可能な管理対象アイテムをアプリ内でプロビジョニングする前に、Google Play に消費リクエストを送信して、消費が正しく記録されたことを示すレスポンスを受け取る必要があります。

消費可能な購入をアプリ内で管理する

消費可能な管理対象アイテムを購入する基本フローは次のとおりです。

  1. getBuyIntent メソッドを呼び出して、購入フローを開始します。
  2. Google Play から返された Bundle を確認して、購入が正常に完了しているか確認します。
  3. 購入が正常に完了していたら、consumePurchase メソッドを呼び出して、購入を消費します。
  4. Google Play から返されたレスポンス コードを確認して、消費が正常に完了しているか確認します。
  5. 消費が正常に完了していたら、アプリ内でアイテムをプロビジョニングします。

その後、ユーザーがアプリを起動したとき、あるいはユーザーがアプリにログインしたときに、ユーザーが未処理の消費可能なアプリ内アイテムを所有していないか確認します。所有していた場合は、そのアイテムの消費とプロビジョニングを行います。アプリ内に消費可能なアプリ内アイテムを実装する場合は、以下のようなアプリ開始フローをおすすめします。

  1. getPurchases リクエストを送信して、ユーザーが所有するアプリ内アイテムを照会します。
  2. 消費可能なアプリ内アイテムがある場合には、consumePurchase を呼び出してアイテムを消費します。アプリが消費アイテムの購入オーダーを完了した後、消費リクエストを送信する前に、アプリが停止したり、接続が切断したりするケースがあり得るため、このステップが必要になります。
  3. Google Play から返されたレスポンス コードを確認して、消費が正常に完了しているか確認します。
  4. 消費が正常に完了していたら、アプリ内でアイテムをプロビジョニングします。

特典購入を設定する

AIDL を使用して特典アイテムを扱うときは、ユーザーが特典を受ける前に購入の「インテント」をキャッシュする必要があります。バックグラウンド スレッドで購入インテントを呼び出すことで、ユーザーが特典を受けるための操作を行うまで、正常に処理されたレスポンス「インテント」を保存しておきます。

SKU をリスト化して読み込む

ユーザーに特典アイテムを付与する前に、getSkuDetails() を呼び出して、アイテム情報を取得します。SKU のリスト内の各特典アイテムに対して、新しい JSON フィールド「rewardToken」が入力されます。

優れたユーザー エクスペリエンスを提供するため、ユーザーに特典アイテムを付与する前に、広告を読み込んで利用可能にしておく必要があります。そのため、バックグラウンド スレッドで getBuyIntentExtraParams() を呼び出します。BILLING_RESPONSE_RESULT_OK レスポンスを受け取ったら、ユーザーに対して特典アイテムを有効にし、返された PendingIntent オブジェクトを、後で使用できるように保存します。特典アイテムに関連付けた広告を読み込むためのプロセスを、以下のコード スニペットに示します。

Kotlin

val rewardToken = skuDetailsJson.optString("rewardToken")
val extraParams = Bundle().putString("rewardToken", rewardToken)

// This call blocks the current thread, so do this in the background.
val buyIntentBundle : Bundle = mService.getBuyIntentExtraParams(9, packageName,
        sku, "inapp", "", extraParams)

val response = buyIntentBundle.getInt("RESPONSE_CODE")
if (response == BILLING_RESPONSE_RESULT_OK) {
    // Enable rewarded product.

    // Save this object for use later.
    val pendingIntentToSave = bundle.getParcelable(RESPONSE_BUY_INTENT)
} else {
    // Don't offer rewarded product.
}

Java

String rewardToken = skuDetailsJson.optString("rewardToken");
Bundle extraParams = new Bundle();
extraParams.putString("rewardToken", rewardToken);

// This call blocks the current thread, so do this in the background.
Bundle buyIntentBundle = mService.getBuyIntentExtraParams(9, getPackageName(),
        sku, "inapp", "", extraParams);

int response = buyIntentBundle.getInt("RESPONSE_CODE");
if (response == BILLING_RESPONSE_RESULT_OK) {
    // Enable rewarded product.

    // Save this object for use later.
    PendingIntent pendingIntentToSave = bundle.getParcelable(RESPONSE_BUY_INTENT);
} else {
    // Don't offer rewarded product.
}

年齢に応じた広告の宣言

児童オンライン プライバシー保護法(COPPA)一般データ保護規則(GDPR)など、子供や未成年のユーザーに関する法的義務を遵守するために、米国内で子供向けとして扱う必要のある広告や、お住まいの国の該当する同意年齢に満たないユーザー向けの広告をアプリで宣言する必要があります。広告リクエストに子供向けのタグを設定すべき条件や、同意年齢に満たないユーザー向けのタグを設定すべき条件、ならびにそれぞれの効果については、AdMob ヘルプセンターをご覧ください。

特典リクエストが子供向けや同意年齢に満たないユーザー向けであることを示すには、以下のコード スニペットのように childDirectedunderAgeOfConsent の追加パラメータを組み込みます。

Kotlin

val rewardToken = skuDetailsJson.optString("rewardToken")
val extraParams = Bundle().putString("rewardToken", rewardToken)
        .putInt("childDirected", ChildDirected.CHILD_DIRECTED)
        .putInt("underAgeOfConsent", UnderAgeOfConsent.UNDER_AGE_OF_CONSENT)

// This call blocks the current thread, so do this in the background.
val buyIntentBundle : Bundle = mService.getBuyIntentExtraParams(9, packageName,
        sku, "inapp", "", extraParams)

Java

Bundle extraParams = new Bundle();
extraParams.putString("rewardToken", rewardToken);
extraParams.putInt("childDirected", ChildDirected.CHILD_DIRECTED);
extraParams.putInt("underAgeOfConsent", UnderAgeOfConsent.UNDER_AGE_OF_CONSENT);

// This call blocks the current thread, so do this in the background.
Bundle buyIntentBundle =
  mService.getBuyIntentExtraParams(
    9, getPackageName(), sku, "inapp", "", extraParams);

ユーザーに特典を付与する前に広告を再生する

ユーザーがボタンをクリックして広告の再生を開始すると、アプリは、保存された PendingIntent オブジェクトを使用して広告の再生を開始できます。これには、startIntentSenderForResult() を呼び出します。

Kotlin

startIntentSenderForResult(
    pendingIntentToSave,
    RC_BUY, Intent(),
    0,
    0,
    0
)

Java

startIntentSenderForResult(pendingIntentToSave, RC_BUY, new Intent(),
        0, 0, 0);

その後、次のコード スニペットに示すように、請求ワークフローの結果を onActivityResult() 内で処理します。広告再生プロセスを処理する場合、Google Play は、他の請求フローと同じように一連のサーバー レスポンス コードを使用します。

Kotlin

fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent) {
    if (requestCode == RC_BUY) {
        int responseCode = data.getIntExtra(RESPONSE_CODE)
        String purchaseData = data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA)
        String signature = data.getStringExtra(RESPONSE_INAPP_SIGNATURE)

        // Handle reward purchase.
    }
}

Java

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == RC_BUY) {
        int responseCode = data.getIntExtra(RESPONSE_CODE);
        String purchaseData = data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA);
        String signature = data.getStringExtra(RESPONSE_INAPP_SIGNATURE);

        // Handle reward purchase.
    }
}

ローカル キャッシュ

Google Play クライアントは、Google Play 請求サービス情報をデバイス上にローカルでキャッシュするようになったため、Google Play Billing API を使用することで、この情報のクエリを頻繁に行うことができます。次の Google Play Billing API 呼び出しは、ネットワーク接続を必要とせず、キャッシュのルックアップによって行われます。そのため、API のレスポンス タイムが飛躍的に短縮されています。

  • getBuyIntent
  • getPurchases
  • isBillingSupported