⚠️注意

Play Billing Libraryの和訳になります。
わかりづらい表現を意訳したり、回りくどいところを端折ったりしています。
和訳に自信がないところもあるため、間違いを見つけた場合は指摘してください。

また、Play Billing Libraryは2017年7月14日現在ではまだプレビュー版なので、将来的に破壊的な変更が加わる可能性がありますので、ご注意ください。

Play Billing Library

Google Playのアプリ内課金は、アプリ内課金リクエストを送信したり、Google Playを使用してアプリ内課金トランザクションを管理するためのシンプルでわかりやすいインターフェースを提供します。
以下の情報は、Play Billing Libraryを使用してアプリからアプリ内課金サービスを呼び出す方法の基本について説明しています。

Play Billing Libraryには便利なクラスと機能があり、これを使用してアプリ内課金サービスとAndroidアプリを統合することができます。
ライブラリは、アプリ内課金サービスへのインタフェースを定義したAndroid Interface Definition Language(AIDL)ファイルのラッパーです。
Play Billing Libraryを使用すると、開発プロセスを単純化することができます。
アプリ内アイテムの表示やアイテムの購入など、アプリ固有のロジックの実装に集中する事ができます。

注:完成した例を見て、アプリをテストする方法については、Play Billing Libraryトレーニングクラスを参照してください。 トレーニングクラスでは、接続の設定、請求リクエストの送信、Google Playからのレスポンス処理、アプリ内課金の管理に関連する重要なタスクを処理するための便利なクラスを含む、完全なアプリ内課金アプリのサンプルを提供します。

Play Billing Libraryリリースdp-1(2017年6月)から、サポートされているAPIレベルの最小値はAndroid 2.2(APIレベル8)です。 サポートされている最低限のアプリ内課金APIはバージョン3です。

注:C ++などの代替言語を使用してアプリケーションにアプリ内課金サービスを統合する場合、またはAIDLファイルと直接対話する場合は、「アプリ内課金を実装する」を参照してください。

始める前に、アプリ内課金の概要を読んで、課金ライブラリを使用してアプリ内課金をスムーズに実装するための概念と用語を理解してください。

Play Billing Libraryを使用するには、次の手順で行います。

  1. AndroidManifest.xmlのアップデート
  2. build.gradleにライブラリを追加
  3. 課金クライアントを作成
  4. アプリ内課金サービスに接続
  5. アプリ内課金サービスにアプリから購入リクエストを送信
  6. GooglePlayからのアプリ内課金レスポンスをハンドリング

AndroidManifest.xml のアップデート

アプリ内課金はアプリとGoogle PlayサーバとのやりとりをGoogle Playアプリに頼っています。
Google Playアプリを使用するには適切なパーミッションをリクストする必要があります。
AndroidManifest.xmlcom.android.vending.BILLINGパーミッションを追加します。
このパーミッションがない場合は、購入リクエストを送ってもGoogle Playがリクエストを拒否してエラーを返します。

下記の行をAndroidManifest.xmlに追加してください。

AndroidManifest.xml
<uses-permission android:name="com.android.vending.BILLING" />

build.gradle にライブラリを追加

build.gradledependenciesに以下の行を追加してください。

build.gradle
dependencies {
    ...
    compile 'com.android.billingclient:billing:dp-1'
}

アプリ内課金サービスに接続

Play Billing Libraryクライアントを使用する前にGoogle Paly のアプリ内課金サービスに以下の手順で接続する必要があります。

  1. Builder()を呼び出してBillingClientのインスタンスを生成します。 また、setListener()メソッドの引数にPurchasesUpdatedListenerのインスタンスの参照を渡して、アプリ内課金やGoogle Playストアでの課金に関するアップデートを受け取る必要があります。
  2. Google Play のアプリ内課金サービスに接続します。 セットアッププロセスは非同期であり、クライアントの設定が完了し、さらにリクエストを行う準備ができた事をBillingClientStateListenerを実装して受け取ります。
  3. onBillingServiceDisconnected()コールバックメソッドをオーバライドし、アプリ内課金サービスの接続が切れた場合の再試行ポリシーを実装します。 たとえば、Playストアサービスがバックグラウンドで更新されている場合、Play Billing Libraryクライアントは接続を失う可能性があります。Play Billing Libraryクライアントはさらにリクエストを行う前にstartConnection()を呼び出して再接続する必要があります。

次のコードサンプルは、接続を開始し、使用準備が完了した事をテストする方法を示しています。

private BillingClient mBillingClient;
...
mBillingClient = new BillingClient.Builder(mActivity).setListener(this).build();
mBillingClient.startConnection(new BillingClientStateListener() {
    @Override
    public void onBillingSetupFinished(@BillingResponse int billingResponseCode) {
        if (billingResponseCode == BillingResponse.OK) {
            // 課金クライアント準備完了。 ここに購入処理を記述。
        }
    }
    @Override
    public void onBillingServiceDisconnected() {
        // startConnection()を呼び出してアプリ内課金サービスに再接続する
    }
});

アプリ内課金リクエストを作成

Play Billing LibraryクライアントがGoogle Playに接続すると、アプリ内アイテムの購入リクエストを開始できます。 Google Playでは、ユーザーが支払い方法を入力するためのチェックアウトインターフェースが用意されているため、アプリで直接支払い取引を処理する必要はありません。
ユーザーが商品を購入すると、Google Playはその商品の所有権を持っていることを認識し、アイテムを消費するまで同じプロダクトIDの商品を購入できないようにします。

ユーザーがアプリ内のアイテムをどのように消費するかを制御し、Google Playにそのアイテムを再び購入可能にするよう通知することができます。 Google Playにクエリを送信して、ユーザーが作成した購入リストをすばやく取得することもできます。 別の端末で購入する場合も考えられるので、アプリ起動時に毎回Google Playに問い合わせてユーザが購入したアイテムが復元されるようにしてください。

アイテムが購入可能か問い合わせる

Play Billing Libraryを使用するとGoogle PlayからユニークなプロダクトIDの商品詳細を非同期で照会することができます。アプリ内課金サービスにリクエストするには、Play Billing LibraryクライアントでquerySkuDetailsAsync()メソッドを呼び出します。このメソッドに購入タイプ(この場合はSkuType.INAPP)とプロダクトID文字列のリストを渡します。

注:クエリを実行するために必要なプロダクトIDをGoogle Playコンソールを使用してアプリの商品リストを作成するときに定義します。 商品リストの作成の詳細については、アプリ内課金の管理を参照してください。

非同期処理の結果をハンドリングするために、SkuDetailsResponseListenerインターフェースを実装する必要があります。
次のサンプルコードに示すように、クエリが終了したときにリスナーに通知するonSkuDetailsResponse()メソッドをオーバーライドできます。

List<String> skuList = new ArrayList<> ();
skuList.add("premiumUpgrade");
skuList.add("gas");
mBillingClient.querySkuDetailsAsync(SkuType.INAPP , skuList,
    new SkuDetailsResponseListener() {
        @Override
        public void onSkuDetailsResponse(SkuDetailsResult result) {
            // Process the result.
        }
    });

リクエストが成功した場合、Play Billing Libraryによって返されたSkuDetailsResultオブジェクトのレスポンスコードはBillingResponse.OK(0)です。
SkuDetailsResultオブジェクトのgetResponseCode()を呼び出してレスポンスコードをチェックすることができます。
Play Billing Library ReferenceでGoogle Playから返されるすべてのレスポンスコードを確認できます。

Play Billing Libraryは、クエリ結果をSkuDetailsオブジェクトのListに格納します。 リストを取得するには、SkuDetailsResultオブジェクトのgetSkuDetailsListメソッドを呼び出します。
リスト内の各SkuDetailsオブジェクトで様々なメソッドを呼び出すことで、そのアイテムの価格や説明などの関連情報を表示できます。
利用可能な商品情報詳細の項目は、SkuDetailsクラスのメソッド一覧を確認してください。

次の例は、前のコードスニペットから返されたSkuDetailsResultオブジェクトから、課金アイテムの価格を取得する方法を示しています。

if (result.getResponseCode() == BillingResponse.OK
                    && result.getSkuDetailsList() != null) {
   for (SkuDetails skuDetails : result.getSkuDetailsList()) {
       String sku = skuDetails.getSku();
       String price = skuDetails.getPrice();
       if ("premiumUpgrade".equals(sku)) mPremiumUpgradePrice = price;
       else if ("gas".equals(sku)) mGasPrice = price;
   }
}

アイテムの購入

アプリで購入リクエストを開始するために、Play Billing LibraryクライアントのlaunchBillingFlow()メソッドを呼び出します。launchBillingFlow()メソッドは必ずUIスレッドから呼び出してください。

注:課金フローを開始する前に、課金ライブラリクライアントのisFeatureSupported()メソッドを呼び出して、デバイスがFeatureType.SUBSCRIPTIONSなどの必要なタイプの購入をサポートしていることや、FeatureType.IN_APP_ITEMS_ON_VRなどで端末が特定機能を備えているかを確認してください。

launchBillingFlow()メソッドに購入するアイテムのプロダクトIDや購入タイプ(この場合はSkuType.INAPP)など、購入をする為に必要なデータを含むBillingFlowParamsオブジェクトを渡します。
BillingFlowParamsのインスタンス生成には、BillingFlowParams.Builderクラスを使用します。

launchBillingFlow()メソッドを呼び出すと、Google Play UIの購入画面が表示されます。
この操作では、次のサンプルコードに示すようにレスポンスコードが返されます。

BillingFlowParams.Builder builder = new BillingFlowParams.Builder()
                                                .setSku(skuId).setType(SkuType.INAPP);
Int responseCode = mBillingClient.launchBillingFlow(builder.build());

Google Playは購入操作の結果を伝えるために、PurchasesUpdatedListenerインターフェイスを実装したリスナーのonPurchasesUpdated()メソッドを呼び出します。
Play Billing Libraryクライアントのインスタンス生成時にsetListener()を用いてこのリスナーを指定します。

次のコードは、onPurchasesUpdated()メソッドをオーバーライドする方法を示しています。

@Override
void onPurchasesUpdated(@BillingResponse int responseCode,
        List<Purchase> purchases) {
    if (responseCode == BillingResponse.OK
            && purchases != null) {
        for (Purchase purchase : purchases) {
            handlePurchase(purchase);
        }
    } else if (responseCode == BillingResponse.USER_CANCELED) {
        // ユーザが購入をキャンセルしたエラーをハンドリング
    } else {
        // その他のエラーをハンドリング
    }
}

注:launchBillingFlow()を呼び出して、購入フローを開始すると、Google PlayではonPurchasesUpdated()の呼び出しが保証されます。startActivityForResult()を呼び出して別のアクティビティを開始すると、onActivityResult()が呼び出されるのと同じように、Google PlayがonPurchasesUpdated()メソッドを呼び出します。 ユーザが購入フローをキャンセルした場合は、Google Playはnullの購入リストとBillingResponse.USER_CANCELEDのレスポンスコードでonPurchasesUpdated()メソッドを呼び出します。

  

セキュリティに関する勧告:Google Playから購入レスポンスを受けとった際に、独自のバッグエンドで安全性の検証を行ってください。Androidアプリはデコンパイルして安全性の検証処理をスタブで置き換えることが出来るため、クライアントを信用してはいけません。Subscriptions and In-App Purchases APIPurchases.productsリソースでget()メソッドを呼び出すか、返されたデータ署名とorderIdを確認してください。orderIdが存在し、以前に処理していない一意の値であることを確認します。もし、静的なレスポンスでテストをした場合はorderIdは返しません。

購入したアイテムを取得

ユーザがアプリで購入したアイテムの購入情報を取得するには、Play Billing LibraryクライアントのqueryPurchases()メソッドを呼び出します。以下の例に示すように、メソッドに購入タイプ(この場合はSkuType.INAPP)を渡します。

PurchasesResult purchasesResult = mBillingClient.queryPurchases(SkuType.INAPP);

Google Play serviceはデバイスにログインしているアカウントの購入情報を返します。
リクエストが成功した場合、Play Billing LibraryはPurchaseオブジェクトのListに問い合わせ結果を格納します。
このリストを受け取るために、PurchasesResultオブジェクトのgetPurchasesList()メソッドを呼び出します。
Purchaseオブジェクトの様々なメソッドを呼び出して、アイテムの購入状態や購入時間などの関連した情報を表示することができます。
利用可能な商品情報詳細の項目は、Purchaseクラスのメソッド一覧を確認してください。

購入アイテムを消費する

Play Billing Libraryを使用して、Google Playで購入したアイテムの所有権を追跡することができます。
ユーザがアイテムを購入すると、そのアイテムは所有されているとみなされ、ユーザはGoogle Playから購入することができません。
Google Playで再度アイテムを購入する前に、アイテムの消費リクエストを送る必要があります。

重要:アプリ内課金アイテムは消費できますが、定期購読はできません。

アプリで購入アイテム消費メカニズムを使用する方法はあなた次第です。
ゲーム内の通貨や装備など、ユーザが複数購入することがある一時的なアイテムに対してアプリ内アイテムの消費を実装するのが一般的です。 ユーザが一度購入し、プレミアムアップグレードなどの永続的な効果をもたらすアイテムの消費を実装することは通常は望ましくはありません。

購入アイテムの消費を記録するには、Play Billing LibraryクライアントでconsumeAsync()メソッドを呼び出し、アプリ内課金サービスで削除する購入アイテムを識別するpurchaseToken文字列を渡します。
また、消費操作の結果をハンドリングするためにConsumeResponseListenerインターフェイスを実装したオブジェクトを渡します。
ConsumeResponseListenerインターフェイスのonConsumeResponse()メソッドをオーバーライドすることで、Play Billing Libraryから操作完了のコールバックを受け取ることができます。

purchaseTokenは、Google Playサービスの購入リクエストの成功よって、Play Billing Libraryから返されるデータの一部で、PurchasesResultオブジェクトのPurchaseオブジェクトリスト内の各Purchaseオブジェクトに格納されています。
Purchaseオブジェクトに対してgetPurchaseToken()メソッドを呼び出して、購入に関連付けられたトークンを取得することができます。

次の例は、関連するpurchaseTokenを使用して購入アイテムを消費する方法を示しています。

ConsumeResponseListener listener = new ConsumeResponseListener() {
    @Override
    public void onConsumeResponse(String outToken, @BillingResponse int responseCode) {
            if (responseCode == BillingResponse.OK) {
                // Handle the success of the consume operation.
                // For example, increase the number of coins inside the user's basket.
    }
};
mBillingClient.consumeAsync(purchaseToken, listener);

購入したアイテムをユーザに反映するのはあなたの責任になります。 たとえば、ユーザーがゲーム内通貨を購入した場合、購入した通貨の分だけプレイヤーの所持金を更新する必要があります。

セキュリティに関する勧告:ユーザに購入したアイテムの効果を付与する前に消費リクエストを送ってください。Google Playから消費リクエストが正常に返っていることを確認してください。

定期購読の実装

定期購読を購入または更新するための課金フローは、アイテム購入のフローと似ていますが、プロダクトタイプにSkuType.SUBSを設定する必要があります。

アプリから購入リクエストを送るために、Play Billing LibraryクライアントのlaunchBillingFlow()メソッドを呼び出します。
課金フローを開始する前にPlay Billing LibraryクライアントのisFeatureSupported()メソッドを呼び出してデバイスが定期購読に対応しているかを確認してください。
launchBillingFlow()メソッドにアイテムのプロダクトIDやプロダクトタイプ(SkuType.SUBS)など購入に必要なデータを含むBillingFlowParamsオブジェクトの参照を渡します。
ユーザが定期購読の更新を行う場合は、addOldSku()
メソッドを使用して、BillingFlowParamsオブジェクトに変更する定期購読のプロダクトIDを渡す必要があります。
BillingFlowParams.Builderクラスを使用してBillingFlowParamsのインスタンスを生成します。

launchBillingFlow()メソッドを呼び出すと、Google Play UIの購入画面が表示されます。
この操作では、次のサンプルコードに示すようにレスポンスコードが返されます。

BillingFlowParams.Builder builder = new BillingFlowParams.Builder()
        .setSku(skuId).setType(SkuType.SUBS);
int responseCode = mBillingClient.launchBillingFlow(builder.build());
// 中断された接続を処理するための再試行ポリシーを必ず実装してください。

Google Playはアイテムの購入の説明の通り、onPurchasesUpdated()コールバックを使用して処理の結果を返します。

メモ

リンク