開発者コンソール

Google Play請求サービスインターフェイスの実装

Google Play請求サービスインターフェイスの実装

このページでは、Appstore請求サービス対応SDKを使用して、アプリにアプリ内課金(IAP)を実装する方法について詳しく説明します。既にアプリにGoogle Play Billing Libraryを統合している場合は、ほとんどの手順でコード変更が不要または最小限で済みます。

詳細なAPIリファレンスについては、Appstore請求サービス対応SDK APIリファレンス(英語のみ)を参照してください。

BillingClientの初期化

ここではコード変更は必要ありません。

Appstore請求サービス対応SDKの手順を実行した後、BillingClientインスタンスを初期化します。BillingClientオブジェクトによって、Appstore請求サービス対応APIとアプリ間の通信が可能になります。BillingClientには、多くの一般的な請求処理に役立つ便利な非同期メソッドが用意されています。

Google Play請求サービスと同様に、一度に作成するBillingClientインスタンスは1つだけにすることを強くお勧めします。ただし、Appstore請求サービス対応SDKでは、一度に複数のBillingClientインスタンスを作成しても、1つの購入イベントに対して複数のPurchasesUpdatedListenerコールバックが発生することはありません。代わりに、BillingClientインスタンスが新しく作成されるたびに、PurchasesUpdatedListenerは新しく提供されたリスナーに更新されます。これは、別のBillingClientインスタンスであっても同様です。

BillingClientは、newBuilder()メソッドを使用して作成します。購入に関する更新情報を受け取るには、setListener()を呼び出してリスナーを追加します。このsetListener()メソッドに、PurchasesUpdatedListenerオブジェクトを渡します。

enablePendingPurchases()メソッドはノーオペレーションメソッドとしてのみ使用できます。保留中の購入を有効にはしません。

次のコードでは、BillingClientを初期化する方法を示します。

private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
    @Override
    public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
        // 実装します 
    }
};

private BillingClient billingClient = BillingClient.newBuilder(context)
    .setListener(purchasesUpdatedListener)
    .enablePendingPurchases()
    .build();

Amazonアプリストアへの接続

ここではコード変更は必要ありません。

Google Playで接続を確立するための要件とは異なり、Amazonアプリストアには接続の維持という概念はありません。Amazonアプリストアでは接続を維持する必要がないため、接続が切断されたかどうかを監視する必要はありません。接続関連のAPIは、常に接続の準備ができていることを想定したノーオペレーションメソッドとしてサポートされます。

startConnection()の呼び出し時には、BillingClientStateListenerは常にBillingResponseCode.OKのコールバックを受け取ります。onBillingServiceDisconnected()メソッドは、ノーオペレーションメソッドとして提供され、Appstore請求サービス対応SDKによって呼び出されることはありません。

以下の例は、Amazonアプリストアに接続する方法を示しています。

billingClient.startConnection(new BillingClientStateListener() {
    @Override
    public void onBillingSetupFinished(BillingResult billingResult) {
        if (billingResult.getResponseCode() == BillingResponseCode.OK) {
            // Appstore請求サービス対応SDKでは、BillingClientStateListenerは常に
            // BillingResponseCode.OKのコールバックを受け取ります。

            // ここで商品や購入をクエリします。
        }
    }

    @Override
    public void onBillingServiceDisconnected() {
        // これはノーオペレーションメソッドであり、Appstore請求サービス対応SDKによって呼び出されることはありません。
    }
});

購入可能な商品の表示

ここではコード変更は必要ありません。

ユーザーに商品を表示する前に、商品の詳細を照会して、ローカライズされた商品情報を取得する必要があります。アプリ内課金(IAP)商品の詳細を照会するには、queryProductDetailsAsync()またはquerySkuDetailsAsync()を呼び出します。

Appstore請求サービス対応SDKから返されるエラーレスポンスコードは、BillingResponseCode.DEVELOPER_ERRORBillingResponseCode.ERRORのみです。Google Play請求サービスでサポートされているほかのエラーレスポンスコードも使用できますが、返されることはありません。

QueryProductDetailsAsync API

queryProductDetailsAsync()メソッドを使用すると、商品の詳細を照会できます。このメソッドはQueryProductDetailsParamsのインスタンスを受け取ります。そのQueryProductDetailsParamsオブジェクトで、Amazon開発者コンソールで作成した商品ID文字列のリストとProductTypeを指定します。消費型アイテムと非消費型アイテムの場合、ProductTypeProductType.INAPPです。定期購入型アイテムの場合、ProductTypeProductType.SUBSです。

定期購入型商品の場合、このAPIは、定期購入オファーの詳細のリストをList<ProductDetails.SubscriptionOfferDetails>として返します。これには、ユーザーが利用できるオファーがすべて含まれています。各オファーには固有のオファートークンがあり、getOfferToken()メソッドを使用してアクセスできます。購入フローを起動するときは、オファートークンを渡す必要があります。1回だけ購入するアプリ内課金(IAP)アイテムのオファーの詳細にアクセスするには、APIレスポンスのgetOneTimePurchaseOfferDetails()メソッドを使用します。

非同期オペレーションの結果を処理するために、queryProductDetailsAsync()メソッドにはリスナーも必要です。このリスナーは、ProductDetailsResponseListenerインターフェイスを実装したものです。このインターフェイスでonProductDetailsResponse()をオーバーライドします。onProductDetailsResponse()メソッドは、商品の詳細の照会が終了するとリスナーに通知します。次に例を示します。

QueryProductDetailsParams queryProductDetailsParams =
    QueryProductDetailsParams.newBuilder()
        .setProductList(
            ImmutableList.of(
                Product.newBuilder()
                    .setProductId("product_id_example")
                    .setProductType(ProductType.INAPP)
                    .build()))
        .build();

billingClient.queryProductDetailsAsync(
    queryProductDetailsParams,
    new ProductDetailsResponseListener() {
        public void onProductDetailsResponse(BillingResult billingResult,
                List<ProductDetails> productDetailsList) {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                // 返されたskuDetailsListを処理します。
            } else if (billingResult.getResponseCode() == BillingResponseCode.ERROR) {
                // エラーレスポンスを処理します。
            } else if (billingResult.getResponseCode() == BillingResponseCode.DEVELOPER_ERROR) {
                // 開発者向けエラーレスポンスを処理します。
            } else {
                // ほかのエラーコードも使用できますが、
                // Appstore請求サービス対応SDKによって返されることはありません。
            }
        }
    }
);

Google Play請求サービスとは異なり、ProductDetails.getTitle()にはアプリ名が含まれていません。

QuerySkuDetailsAsync API

querySkuDetailsAsync()メソッドを使用すると、SKUの詳細を照会できます。このメソッドはSkuDetailsParamsのインスタンスを受け取ります。このインスタンスで、Amazon開発者コンソールで作成したSKU文字列のリストとSkuTypeを指定します。消費型アイテムと非消費型アイテムの場合、SkuTypeSkuType.INAPPです。定期購入型アイテムの場合、SkuTypeSkuType.SUBSです。

非同期オペレーションの結果を処理するために、querySkuDetailsAsync()にはリスナーも必要です。このリスナーは、SkuDetailsResponseListenerインターフェイスを実装したものです。このインターフェイスでonSkuDetailsResponse()をオーバーライドします。onSkuDetailsResponse()メソッドは、SKUの詳細の照会が終了するとリスナーに通知します。次に例を示します。

SkuDetailsParams skuDetailsParams =
    SkuDetailsParams.newBuilder()
            .setType(BillingClient.SkuType.INAPP)
            .setSkusList(skusList)
            .build();

billingClient.querySkuDetailsAsync(
    skuDetailsParams,
    new SkuDetailsResponseListener() {
        public void onSkuDetailsResponse(BillingResult billingResult,
               List<SkuDetails> skuDetailsList) {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                // 返されたskuDetailsListを処理します。
            } else if (billingResult.getResponseCode() == BillingResponseCode.ERROR) {
                // エラーレスポンスを処理します。
            } else if (billingResult.getResponseCode() == BillingResponseCode.DEVELOPER_ERROR) {
                // 開発者向けエラーレスポンスを処理します。
            } else {
                // ほかのエラーコードも使用できますが、
                // Appstore請求サービス対応SDKによって返されることはありません。
            }
        }
    }
);

購入フローの起動

ここでは最小限のコード変更が必要になります。

Google Play請求サービスとは異なり、Appstore請求サービス対応SDKでは、1回の購入で最大1つの商品しか購入できません。リストに複数のアイテムがある場合は、BillingResponseCode.FEATURE_NOT_SUPPORTEDというエラーが返されます。

アプリで購入フローを開始するには、アプリのメインスレッドからlaunchBillingFlow()を呼び出します。launchBillingFlow()メソッドはBillingFlowParamsオブジェクトを受け取ります。このオブジェクトにはProductDetailsオブジェクトが含まれています。ProductDetailsを取得するには、queryProductDetailsAsync()を呼び出します。BillingFlowParamsオブジェクトは、BillingFlowParams.Builderクラスを使用して作成します。以下の例は、請求フローを起動する方法を示しています。

// 請求フローが起動されるアクティビティの参照
Activity activity = ...;

ImmutableList productDetailsParamsList =
    ImmutableList.of(
        ProductDetailsParams.newBuilder()
             // queryProductDetailsAsyncを呼び出してproductDetailsを取得します
            .setProductDetails(productDetails)
            .build()
    );

BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(productDetailsParamsList)
    .build();

// 請求フローを起動します
BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);

次のコードは、購入のオファートークンを設定する例を示しています。オファートークンの詳細については、QueryProductDetailsAsync APIを参照してください。

BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setOfferToken(offerDetails.getOfferToken())
.build();

または、次に示すように、querySkuDetailsAsync()の呼び出しから取得したSkuDetailsオブジェクトを使用して、BillingFlowParamsオブジェクトを初期化することもできます。

BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
     .setSkuDetails(skuDetails)
     .build();

BillingClientを初期化するときに、setLister()を使用してPurchasesUpdatedListenerの実装をリスナーとして追加しました。このリスナーはonPurchasesUpdated()メソッドをオーバーライドし、購入の結果を返します。onPurchasesUpdated()の実装では、次の例に示すように、考えられるレスポンスコードを処理する必要があります。

@Override
void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
    if (billingResult.getResponseCode() == BillingResponseCode.OK) {
        for (Purchase purchase : purchases) {
            handlePurchase(purchase);
        }
    } else if (billingResult.getResponseCode() == BillingResponseCode.ERROR) {
        // 購入フローのエラーを処理します。
    } else if (billingResult.getResponseCode() == BillingResponseCode.DEVELOPER_ERROR) {
        // 購入フローの開発者向けエラーを処理します。
    } else {
        // ほかのエラーコードも使用できますが、
        // Appstore請求サービス対応SDKによって返されることはありません。
    }
}

Appstore請求サービス対応SDKから返されるエラーレスポンスコードは、BillingResponseCode.DEVELOPER_ERRORBillingResponseCode.ERRORのみです。Google Play請求サービスでサポートされているほかのエラーレスポンスコードも使用できますが、返されることはありません。

購入が成功すると、購入トークンが生成されます。購入トークンは購入を一意に識別するもので、ユーザーとその購入に関連付けられた商品IDを表します。

サポート対象外のフィールド

Google Play請求サービスで利用可能な以下のフィールドは、Appstore請求サービス対応SDKではサポートされていません。これらのフィールドへの参照はコードから削除してください。

リクエストフィールド:

  • アカウント識別子(難読化されたアカウントIDと難読化されたプロファイルID)
  • VR購入フロー

レスポンスフィールド:

  • アカウント識別子(難読化されたアカウントIDと難読化されたプロファイルID)
  • 注文ID
  • 署名
  • パッケージ名
  • 承認済み

注: Appstore請求サービス対応SDKは、上記のフィールドを除く、IAB-4.0の仕様に存在するフィールドのみをサポートしています。

購入の処理

ここでは最小限のコード変更が必要になります。

ユーザーが購入を完了したら、アプリはその購入を処理する必要があります。通常、アプリへの購入の通知はPurchasesUpdatedListenerを通じて行われます。ただし、購入の取得で説明するように、アプリでqueryPurchasesAsync()を使用して購入を取得する場合もあります。

購入が完了したら、アプリからユーザーにコンテンツを提供する必要があります。非消費型アイテムの場合は、acknowledgePurchase()を使用してコンテンツの配信を承認します。消費型アイテムの場合は、consumeAsync()を呼び出して承認し、そのアイテムを消費済みとしてマークします。

AmazonアプリストアにおけるGoogle Play請求サービスAPIインターフェイスとGoogle Play Billing Libraryの違いは以下のとおりです。

  • 消費型アイテムについてacknowledgePurchase()を呼び出すと、そのアイテムは承認されるだけでなく消費されます。非消費型アイテムまたは定期購入型アイテムについてconsumeAsync()を呼び出すと、そのアイテムは承認されるだけで消費はされません。これは、Google Play請求サービスとは異なり、Appstore請求サービス対応SDKでは消費型アイテムと非消費型アイテムが内部で別々のエンティティと見なされるためです。
  • Appstore請求サービス対応SDKでは、消費型アイテムが購入済みでまだ消費されていない場合でも、そのアイテムを再購入できます(前回の購入時にconsumeAsync()が呼び出されなかった場合に発生する可能性があります)。
  • 購入が承認されない場合、ユーザーが自動的に返金を受け取ることはありません。これはGoogle Play請求サービスとは異なります。Google Play請求サービスでは、Android開発者向けドキュメントに記載されているとおり、3日間にわたって未承認の購入は取り消されます。

以下の例は、関連付けられた購入トークンを使用して商品を使用する方法を示しています。

void handlePurchase(Purchase purchase) {
    // queryPurchasesAsyncまたはPurchasesUpdatedListenerから購入を取得します。
    if (purchase.getPurchaseState() != PurchaseState.PURCHASED) {
        return;
    }

    // アイテムをユーザーに配信します。

    // アイテムを消費します。
    ConsumeParams consumeParams =
        ConsumeParams.newBuilder()
            .setPurchaseToken(purchase.getPurchaseToken())
            .build();

    ConsumeResponseListener listener = new ConsumeResponseListener() {
        @Override
        public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                // 消費オペレーションの成功を処理します。
            } else if (billingResult.getResponseCode() == BillingResponseCode.ERROR) {
                // エラーレスポンスを処理します。
            } else {
                // ほかのエラーコードも使用できますが、
                // Appstore請求サービス対応SDKによって返されることはありません。
            }
        }
    };

    billingClient.consumeAsync(consumeParams, listener);
}

同様に、以下の例は、関連付けられた購入トークンを使用して購入の承認を行う方法を示しています。

void handlePurchase(Purchase purchase) {
    if (purchase.getPurchaseState() == PurchaseState.PURCHASED) {
        AcknowledgePurchaseParams acknowledgePurchaseParams =
            AcknowledgePurchaseParams.newBuilder()
                .setPurchaseToken(purchase.getPurchaseToken())
                .build();

        AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = ...

        billingClient.acknowledgePurchase(
            acknowledgePurchaseParams,
            acknowledgePurchaseResponseListener);
    }
}

アイテムの消費時にAppstore請求サービス対応SDKから返されるエラーレスポンスコードは、BillingResponseCode.ERRORのみです。Google Play請求サービスでサポートされているほかのエラーレスポンスコードも使用できますが、返されることはありません。

購入の取得

ここでは最小限のコード変更が必要になります。

PurchasesUpdatedListenerでリッスンするとアプリに購入が通知されますが、状況によっては、ユーザーによる購入がアプリに認識されないことがあります。アプリで購入を認識できない可能性があるのは、次のようなシナリオです。

  • ネットワークの問題: ユーザーが購入を正常に完了したものの、PurchasesUpdatedListenerを通じて購入が通知される前にデバイスのネットワーク接続に問題が発生した場合。
  • 複数のデバイス: ユーザーがあるデバイスでアイテムを購入し、別のデバイスに切り替えて、購入したアイテムを表示しようとした場合。
  • 定期購入型アイテムのライフサイクルイベント: 更新などの定期購入型アイテムのライフサイクルイベントは、請求クライアントからのAPI呼び出しなしで定期的に発生します。

これらのシナリオを処理するには、onResume()メソッドでqueryPurchasesAsync()を呼び出します。こうすることで、購入の処理で説明されているように、すべての購入が正常に処理されます。Google Play請求サービスとは異なり、queryPurchasesAsync()はローカルキャッシュの有効期限が切れるとネットワーク呼び出しを行うため、リスナーコールバックが発生するまでの時間に影響が及びます。Appstore請求サービス対応SDKで呼び出し時間を短縮するには、queryPurchasesAsync()呼び出しでのSKUの数を100に制限します。

queryPurchasesAsync()メソッドでは、非消費型アイテム、消費されていない消費型アイテム、アクティブな定期購入型アイテムのアプリ内課金のみが返されます。以下の例は、ユーザーのアプリ内課金を取得する方法を示しています。

billingClient.queryPurchasesAsync(
    QueryPurchasesParams.newBuilder()
      .setProductType(ProductType.INAPP)
      .build(),
    new PurchasesResponseListener() {
      public void onQueryPurchasesResponse(BillingResult billingResult, List purchases) {
        if (billingResult.getResponseCode() == BillingResponseCode.OK) {
            // 返された購入リストを処理します(ユーザーが所有するアプリ内課金(IAP)アイテムを表示します)。
        } else if (billingResult.getResponseCode() == BillingResponseCode.ERROR) {
            // エラーレスポンスを処理します。
        } else if (billingResult.getResponseCode() == BillingResponseCode.DEVELOPER_ERROR) {
            // 開発者向けエラーレスポンスを処理します。
        } else {
            // ほかのエラーコードも使用できますが、
            // Appstore請求サービス対応SDKによって返されることはありません。
        }
      }
    }
);

定期購入型アイテムを対象にする場合は、次に示すように、QueryPurchasesParamsの作成時にProductType.SUBSを渡します。

QueryPurchasesParams.newBuilder()
.setProductType(ProductType.SUBS)
.build()

または、次に示すように、QueryPurchasesParamsオブジェクトの代わりにSkuTypeを指定する文字列を指定して、queryPurchasesAsync()を呼び出すこともできます。

billingClient.queryPurchasesAsync(
     SkuType.INAPP,
     purchasesResponseListener
 );

Appstore請求サービス対応SDKから返されるエラーレスポンスコードは、BillingResponseCode.DEVELOPER_ERRORBillingResponseCode.ERRORのみです。Google Play請求サービスでサポートされているほかのエラーレスポンスコードも使用できますが、返されることはありません。

Google Play請求サービスとは異なり、消費されていない消費型アイテム(consumeAsync()が呼び出されなかった場合)は、アイテムの購入が行われたデバイスにのみ返され、ほかのデバイスには返されません。同じデバイスでアプリのバージョンが変更された場合(アプリのアップグレード時など)、まだ消費されていない消費型アイテムはすぐには返されない可能性がありますが、最終的には返されます。

サポート対象外のフィールド

Google Play請求サービスで利用可能な以下のレスポンスフィールドは、Appstore請求サービス対応SDKではサポートされていません。これらのフィールドへの参照はコードから削除してください。

  • アカウント識別子(難読化されたアカウントIDと難読化されたプロファイルID)
  • 注文ID
  • 署名
  • パッケージ名
  • 承認済み

注: Appstore請求サービス対応SDKは、上記のフィールドを除く、IAB-4.0の仕様に存在するフィールドのみをサポートしています。

サポート対象外の機能

Appstore請求サービス対応SDKでは、以下の機能とAPIはサポートされていません。

アプリのテスト

アプリをテストし、Appstore請求サービス対応SDKとの統合を検証するには、次のガイドラインに従ってください。

  • ライブアプリテストサービスを使用して、特定のユーザーグループを対象に本番環境でアプリをテストします。
  • ライブアプリテストを開始する前に、Appstore請求サービス対応SDKを組み込んだアプリのアプリ内課金(IAP)アイテムを作成・申請します。
  • Amazon開発者コンソールに表示されるアプリ内課金(IAP)アイテムのSKUは、Google Playコンソールに表示されるアプリの商品IDと同じものにします。そうしない場合、アプリの商品IDも更新する必要があります。

Last updated: 2023年10月27日