Google Play Billing Library 4 または 5 からバージョン 6 に移行する

このトピックでは、Google Play Billing Library 4 または 5 から Google Play Billing Library 6 に移行する方法と、新しい定期購入機能の使用方法について説明します。

バージョン 6.0.0 の変更点をすべて網羅したリストについては、リリースノートをご覧ください。

概要

Google Play Billing Library 6 は、バージョン 5 で導入された新しい定期購入機能を基盤とし、いくつかの改善を行っています。これらの機能により、多様な方法で定期購入を販売できるようになります。増え続ける SKU を作成し管理する必要がなくなるため、運用コストを削減できます。

Google Play Billing Library 5 で導入された新機能の詳細については、Google Play Console での定期購入に関する最近の変更をご覧ください。

下位互換性のある Play Billing Library のアップグレード

既存の定期購入商品はすべてこの新しいパラダイムに自動的に変換されました。これは 2022 年 5 月の Play Billing Library 5 のリリースと新しい定期購入プラットフォームの一環として行われました。つまり、新しいバージョンの Play Billing Library と互換性のあるカタログを使用するために、定期購入アイテム構成を変更する必要はありません。定期購入の SKU が下位互換性のある定期購入にどのように変換されたかについて詳しくは、Google Play Console のヘルプ記事の「以前の定期購入の使用」セクションをご覧ください。

古いバージョンのアプリは引き続き機能

下位互換性のある定期購入カタログを使用する場合、既存のバージョンのアプリはすべて、引き続きそのアイテムの意図するとおりに機能します。1 回限りのアイテムの購入も、古いバージョンで引き続き問題なく機能します。

サポート終了のメソッド(querySkuDetailsAsync() など)を使用しているアプリのバージョンでは、下位互換性のない基本プランや特典を販売できなくなります。下位互換性のある特典については、関連する Google Play Console ヘルプセンター記事をご覧ください。

Play Billing Library 5 または 6 へのアップグレード

Play Billing Library 5 と 6 には、サポートが終了したメソッド querySkuDetailsAsyncBillingFlowParams.Builder.setSkuDetails が含まれており、課金フロー パラメータとして SkuDetails を受け取ります。つまり、さまざまな移行ステージをプランニングして、段階的に Play Billing Library 6 に移行できます。

移行の最初のステップとして、ライブラリのバージョンを更新し、カタログとバックエンドはそのままにして、サポートが終了したメソッドを使用した状態でアプリをテストします。queryPurchaseslaunchPriceChangeFlowsetVrPurchaseFlow を使用していない場合、意図したとおりに機能します。その後、2022 年 5 月にリリースされた新しい定期購入機能を全面的に導入できます。

以前に Google Play Billing Library 5 の移行でこれらの機能を導入している場合は、Google Play Billing Library を更新するユーザーの定期購入を変更するとラベルが付いたセクションに進んでください。以前のバージョンから始める場合、または新機能を完全には導入していない場合は、完全な移行手順を読み、導入方法をご確認ください。

完全な移行手順

バックエンドの商品カタログで新しい定期購入を作成する

基本プランは Google Play Console または Play Developer API を使用して設定します。1 つの定期購入に複数の基本プラン(それぞれに複数の特典付き)を設定できます。定期購入の特典では、柔軟な価格モデルと利用資格オプションを提供できます。さまざまな自動更新とプリペイド プランを使用して、定期購入のライフサイクル全体で特典を作成できます。

アプリを移行する前に、Play Billing Library 6 の統合の新しい定期購入プラットフォームのエンティティ構造に沿って、新しい商品を作成することをおすすめします。以前のカタログで利用資格の特典が同じである重複する商品を 1 つの定期購入に統合できます。また、基本プランと特典の構成を使用して、提供したいすべてのオプションを表せます。この推奨事項について詳しくは、Google Play Console ヘルプセンター記事の「以前の定期購入の使用」セクションをご覧ください。

変換済みの定期購入商品は 2022 年 5 月のリリース以降変更しないことをおすすめします。サポート終了のメソッド(例: querySkuDetailsAsync())を使用しているバージョンのアプリで販売するために、これらの以前のビルドに影響を与える可能性がある変更を導入せずに、そのままにしておく必要があります。

変換プロセスでは、既存の統合に問題を引き起こす可能性がある偶発的な変更が行われないよう、2022 年 5 月より前にカタログにあった定期購入商品を読み取り専用にしています。これらの定期購入に変更を加えることは可能ですが、フロントエンドとバックエンドの統合に影響を及ぼす可能性があります。

  • フロントエンドでは、querySkuDetailsAsync() を使用して定期購入商品の詳細を取得するアプリのバージョンで、下位互換性のある基本プランと特典のみを販売できます。また下位互換性のある基本プランと特典の組み合わせは 1 つのみです。新しいプランまたは特典を変換済みの定期購入に追加すると、新しい追加の基本プランまたは特典を以前のバージョンのアプリで販売できなくなります。

  • バックエンドでは、Google Play Console の UI で変換済みの定期購入を編集する場合、これらを inappproducts エンドポイントで管理できなくなります(この目的のためにエンドポイントを呼び出していた場合)。また、このような定期購入を管理するには、新しい定期購入ステータス エンドポイント(purchases.subscriptionsv2.get)に移行する必要があります。以前の購入ステータス エンドポイント(purchases.subscriptions.get)の場合、下位互換性のある基本プランと特典の購入を処理するために必要なデータのみを返すためです。詳しくは、定期購入ステータスの管理セクションをご覧ください。

新しい API でバックエンドの定期購入カタログを管理する

Google Play Developer API で定期購入商品カタログを自動的に管理する場合は、新しい定期購入商品定義エンドポイントを使用して、定期購入、基本プラン、特典を作成、管理する必要があります。このリリースの商品カタログ API の変更について詳しくは、2022 年 5 月の定期購入の機能に関するガイドをご覧ください。

Google Play 請求サービスの定期購入の自動商品カタログ管理モジュールを移行するには、inappproducts API を新しい Subscription Publishing API に置き換えて、定期購入カタログを管理、公開します。新しいエンドポイントは 3 つあります。

これらの新しいエンドポイントには、基本プランと特典タグ、地域ターゲティング、プリペイド プランなど、カタログの新機能を活用するために必要な機能がすべて備わっています。

1 回だけの購入商品のためにアプリ内商品カタログを管理するには、引き続き inappproducts API を使用する必要があります。

サポート終了のメソッド(querySkuDetailsAsync() など)を使用しているバージョンのアプリで、下位互換性のない基本プランや特典を販売できなくなります。下位互換性のある特典について詳しくは、こちらをご覧ください。

Google Play Billing Library を更新する

新しい定期購入商品カタログを作成したら、アプリを Google Play Billing Library 5 に移行できます。アプリの build.gradle ファイルで、既存の Play Billing Library の依存関係を最新バージョンに置き換えます。

dependencies {
    def billingVersion = "6.0.0"

    implementation "com.android.billingclient:billing:$billingVersion"
}

Play Billing Library 6 には下位互換性があるため、メソッドの呼び出しを修正していなくても、プロジェクトはすぐにビルドされます。SKU の概念はサポート終了と見なされますが、アプリの移植をより簡単に、より段階的なプロセスで進められるよう引き続き残ります。

BillingClient を初期化して Google Play への接続を確立する

Android アプリから購入を開始するための最初のステップに変更はありません。

購入可能なアイテムを表示する

ユーザーが購入できるすべての特典を取得するには次の操作を行います。

  • SkuDetailsParamsQueryProductDetailsParams に置き換えます。
  • BillingClient.querySkuDetailsAsync() の呼び出しを、BillingClient.queryProductDetailsAsync() を使用するように切り替えます。

クエリ結果が SkuDetails から ProductDetails に変化しているはずです。個々の ProductDetails アイテムには、アイテムに関する情報(ID、タイトル、タイプなど)が含まれています。定期購入アイテムの場合、ProductDetails には List<ProductDetails.SubscriptionOfferDetails>(定期購入の特典の詳細を示すリスト)が含まれています。1 回だけの購入アイテムの場合、ProductDetails には ProductDetails.OneTimePurchaseOfferDetails が含まれています。これらを使用して、どの特典をユーザーに表示するかを決定できます。

次の例は、アプリの変更前と変更後のコードを示しています。

変更前

Kotlin

val skuList = ArrayList<String>()

skuList.add("up_basic_sub")

val params = SkuDetailsParams.newBuilder()

params.setSkusList(skuList).setType(BillingClient.SkuType.SUBS).build()

billingClient.querySkuDetailsAsync(params) {
    billingResult,
    skuDetailsList ->
    // Process the result
}

Java

List<String> skuList = new ArrayList<>();

skuList.add("up_basic_sub");

SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();

params.setSkusList(skuList).setType(SkuType.SUBS).build();

billingClient.querySkuDetailsAsync(params,
    new SkuDetailsResponseListener() {
        @Override
        public void onSkuDetailsResponse(BillingResult billingResult,
                List<SkuDetails> skuDetailsList) {
            // Process the result.
        }
    }
);

変更後

Kotlin

val productList =
    listOf(
        QueryProductDetailsParams.Product.newBuilder()
            .setProductId("up_basic_sub")
            .setProductType(BillingClient.ProductType.SUBS)
            .build()
    )

val params = QueryProductDetailsParams.newBuilder().setProductList(productList).build()

billingClient.queryProductDetailsAsync(params) {
    billingResult,
    productDetailsList ->
    // Process the result
}

Java

ImmutableList<Product> productList = ImmutableList.of(Product.newBuilder()
                                            .setProductId("up_basic_sub")
                                            .setProductType(ProductType.SUBS)
                                            .build());

QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder()
    .setProductList(productList)
    .build();

billingClient.queryProductDetailsAsync(
        params,
        new ProductDetailsResponseListener() {
                public void onProductDetailsResponse(BillingResult billingResult, List<ProductDetails> productDetailsList) {
                    // Process the result
                }
        }
);

queryProductDetailsAsync のコールバックは List<ProductDetails> を返します。個々の ProductDetails アイテムには、アイテムに関する情報(ID、タイトル、タイプなど)が含まれています。主な違いとしては、定期購入アイテムにはユーザーが購入できるすべての特典を含む List<ProductDetails.SubscriptionOfferDetails> も表示されるようになっています。

以前のバージョンの Play Billing Library は新しいオブジェクト(定期購入、基本プラン、特典など)をサポートしていないため、新しいシステムではこれまでの定期購入 SKU をそれぞれ下位互換性のある基本プランと特典に変換します。在庫のある 1 回だけ購入アイテムも ProductDetails オブジェクトに移行されています。1 回だけの購入アイテムの特典詳細にアクセスするには、getOneTimePurchaseOfferDetails() メソッドを使用します。

まれに、一部のデバイスでは Google Play 開発者サービスのバージョンが古いことが原因で、ProductDetailsqueryProductDetailsAsync() に対応していない場合があります。適切にこのシナリオに対応できるようにするには、queryProductDetailsAsync を呼び出す前に、PRODUCT_DETAILS 機能の isFeatureSupported() を呼び出します。レスポンスが OK であれば、デバイスはこの機能に対応しており、queryProductDetailsAsync() を呼び出せます。レスポンスが FEATURE_NOT_SUPPORTED の場合は、代わりに querySkuDetailsAsync() を使用して、利用可能な下位互換性のあるアイテムのリストをリクエストします。下位互換性がある機能の使用方法について詳細は、2022 年 5 月の定期購入機能ガイドをご覧ください。

特典購入フローを開始する

特典購入フローを開始する方法は、SKU のフローを開始する方法と非常によく似ています。バージョン 6 で購入リクエストを開始する方法は次のとおりです。

  • BillingFlowParams には、SkuDetails でなく ProductDetailsParams を使用します。
  • 特典 ID や基本プラン ID などの特典の詳細は、SubscriptionOfferDetails オブジェクトを使用して取得できます。

ユーザーが選択した特典付きでアイテムを購入するには、選択された特典の offerToken を取得して ProductDetailsParams オブジェクトに渡します。

BillingFlowParams オブジェクトの作成後、BillingClient で請求フローを開始する方法に変更はありません。

次の例は、アプリの変更前と変更後のコードを示しています。

変更前

Kotlin

// An activity reference from which the billing flow will be launched.
val activity : Activity = ...
// Retrieve a value for "skuDetails" by calling querySkuDetailsAsync().
val billingFlowParams = BillingFlowParams.newBuilder()
                            .setSkuDetails(skuDetails)
                            .build()

val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)

Java

// An activity reference from which the billing flow will be launched.
Activity activity = ...;
// Retrieve a value for "skuDetails" by calling querySkuDetailsAsync().
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
        .setSkuDetails(skuDetails)
        .build();

BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)

変更後

Kotlin

// An activity reference from which the billing flow will be launched.
val activity : Activity = ...;

val productDetailsParamsList = listOf(
    BillingFlowParams.ProductDetailsParams.newBuilder()
        // retrieve a value for "productDetails" by calling queryProductDetailsAsync()
        .setProductDetails(productDetails)
        // For One-time product, "setOfferToken" method shouldn't be called.
        // For subscriptions, to get the offer token corresponding to the selected
        // offer call productDetails.subscriptionOfferDetails?.get(selectedOfferIndex)?.offerToken
        .setOfferToken(selectedOfferToken)
        .build()
)

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

// Launch the billing flow
val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)

Java

// An activity reference from which the billing flow will be launched.
Activity activity = ...;

ImmutableList<ProductDetailsParams> productDetailsParamsList =
    ImmutableList.of(
        ProductDetailsParams.newBuilder()
             // retrieve a value for "productDetails" by calling queryProductDetailsAsync()
            .setProductDetails(productDetails)
            // For one-time products, "setOfferToken" method shouldn't be called.
            // For subscriptions, to get the offer token corresponding to the selected
            // offer call productDetails.getSubscriptionOfferDetails().get(selectedOfferIndex).getOfferToken()
            .setOfferToken(selectedOfferToken)
            .build()
    );

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

// Launch the billing flow
BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);

購入を処理する

Google Play Billing Library 6 で購入を処理する方法は、以前のバージョンとほとんど変わりがありません。

ユーザーが所有するアクティブな購入をすべて取得して新しい購入を照会するには、次の手順を行います。

  • BillingClient.SkuType 値を queryPurchasesAsync() に渡す代わりに、BillingClient.ProductType 値を含む QueryPurchasesParams オブジェクトを渡します。

次の例は、アプリの変更前と変更後のコードを示しています。

変更前

Kotlin

billingClient.queryPurchasesAsync(BillingClient.SkuType.SUBS) {
    billingResult,
    purchaseList -> {
        // Process the result
    }
}

Java

billingClient.queryPurchasesAsync(
    BillingClient.SkuType.SUBS,
    new PurchasesResponseListener() {
        public void onQueryPurchasesResponse(
                BillingResult billingResult,
                ListP<urchase >purchases) {
            // process the result
        }
    }
);

変更後

Kotlin

billingClient.queryPurchasesAsync(
    QueryPurchasesParams.newBuilder()
        .setProductType(BillingClient.ProductType.SUBS)
        .build()
) { billingResult, purchaseList ->
    // Process the result
}

Java

billingClient.queryPurchasesAsync(
    QueryPurchasesParams.newBuilder().setProductType(ProductType.SUBS).build(),
    new PurchasesResponseListener() {
        public void onQueryPurchasesResponse(
                BillingResult billingResult,
                List<Purchase> purchases) {
            // Process the result
        }
    }
);

アプリ外で行われた購入保留中の取引を管理する手順に変更はありません。

新しい API でバックエンドの定期購入ステータスを管理する

前の手順で作成した新しい商品の購入を処理できるように、バックエンドの定期購入ステータス管理コンポーネントを移行する必要があります。現在の定期購入ステータス管理コンポーネントは、2022 年 5 月のリリース前に定義した変換済み定期購入商品に対して通常どおり機能します。下位互換性のある特典の購入を管理するには十分ですが、新しい機能はサポートしていません。

定期購入ステータス管理モジュールに新しい Subscription Purchases API を実装する必要があります。このモジュールは購入ステータスを確認し、バックエンドで Play Billing 定期購入の利用資格を管理します。以前のバージョンの API では、新しいプラットフォームで購入を管理するために必要なすべての詳細が返されるわけではありません。以前のバージョンからの変更点について詳しくは、2022 年 5 月の定期購入の新機能に関するガイドをご覧ください。

通常は、SubscriptionNotification リアルタイム デベロッパー通知を受け取るたびに Subscription Purchases API を呼び出して、定期購入ステータスに関する最新情報を取得しています。purchases.subscriptions.get の呼び出しを、Subscription Purchases API の新しいバージョンである purchases.subscriptionsv2.get に置き換える必要があります。SubscriptionPurchaseV2 という新しいリソースがあり、新しいモデルで定期購入の利用資格を管理するために必要な情報が提供されます。

この新しいエンドポイントは、すべての定期購入商品とすべての購入のステータスを、販売したアプリのバージョンや商品が定義された日時(2022 年 5 月のリリース前またはリリース後)に関係なく返します。移行後はこのバージョンの定期購入ステータス管理モジュールのみが必要になります。

ユーザーの定期購入を変更する

Play Billing Library 5 以前は ProrationMode を使用して、ユーザーの定期購入の変更(アップグレードやダウングレードなど)を適用していました。これはバージョン 6 では非推奨になり、ReplacementMode に置き換えられています。

定期購入の価格変更を処理する

以前にサポート終了となった launchPriceConfirmationFlow API は、Play Billing Library 6 から削除されています。代替の方法については、価格変更ガイドをご覧ください。

Play Billing Library のエラーに対応する

Play Billing Library 6 には、新しい NETWORK_ERROR コードが追加されています。これはユーザーのデバイスと Google Play システム間のネットワーク接続の問題を示すものです。コード SERVICE_TIMEOUTSERVICE_UNAVAILABLE も変更されました。詳しくは、BillingResult のレスポンス コードを処理するをご覧ください。

保留中のトランザクションを処理する

バージョン 6.0.0 以降では、保留中の購入の注文 ID は Play Billing Library で作成されません。このような購入の場合、購入ステータスが PURCHASED に移行した後に注文 ID が入力されます。統合ではトランザクションが完全に終了した後にのみ、注文 ID が入力されることを考慮する必要があります。引き続きレコードには購入トークンを使用できます。保留中の購入の処理について詳しくは、Play Billing Library の統合ガイド購入ライフサイクル管理ガイドをご覧ください。