1 回限りのアイテムの予約購入特典を追加する

1. はじめに

この Codelab では、1 回限りのアイテム(OTP)の作成に焦点を当て、そのアイテムの予約購入特典を追加します。

: この Codelab を開始する前に、1 回限りのアイテムの EAP お問い合わせフォームに記入して、予約購入機能へのアクセスをリクエストする必要があります。

対象

この Codelab は、1 回限りのアイテムについて理解しており、1 回限りのアイテムに予約購入特典を追加する方法を把握したいと考えている Android アプリ デベロッパーを対象としています。

前提条件

1 回限りのアイテムを初めて使用する場合は、地域の商品価格設定で新しい市場を開拓する Codelab を完了することをおすすめします。

学習内容

  • Google Play Console を使用して、1 回限りのアイテムの予約購入特典を作成する方法。
  • Play Billing Library API を使用して、1 回限りのアイテムと対応する予約購入特典の詳細をクエリする方法。

必要なもの

2. サンプルアプリをビルドする

この Codelab では、サンプルの Android アプリを使用して、1 回限りのアイテムを管理する方法を説明します。このサンプルアプリは、次の側面を示す完全なソースコードを備えた、完全に機能する Android アプリとして設計されています。

  • アプリを PBL と統合します。
  • 1 回限りのアイテムと関連する予約購入特典の取得。
  • 地域別価格の購入フローを実行します。

次のデモ動画は、サンプルアプリをデプロイして実行した後の外観と動作を示しています。

1 回限りのアイテムと Google Play Billing Library(PBL)にすでに精通している場合は、サンプルアプリをダウンロードして試すことができます。

前提条件

サンプルアプリをビルドしてデプロイする前に、次の操作を行います。

ビルド

このビルドステップの目的は、サンプルアプリの署名付き Android App Bundle ファイルを生成することです。

Android App Bundle を生成する手順は次のとおりです。

  1. GitHub からサンプルアプリをダウンロードします。
  2. サンプルアプリをビルドします。ビルドする前に、サンプルアプリのパッケージ名を変更してからビルドします。Google Play Console に他のアプリのパッケージがある場合は、サンプルアプリに指定するパッケージ名が一意であることを確認してください。

    : サンプルアプリをビルドすると、ローカルテストで使用できる APK ファイルのみが作成されます。ただし、Google Play Console でアイテムが設定されていないため、アプリを実行してもアイテムと価格は取得されません。
  3. 署名付きの Android App Bundle を生成します。
    1. アップロード鍵とキーストアを生成する
    2. アップロード鍵でアプリに署名する
    3. Play アプリ署名を設定する

次のステップは、Android App Bundle を Google Play Console にアップロードすることです。

3. Google Play Console で予約購入の OTP を作成する

Google Play Console で 1 回限りのアイテム(OTP)を作成するには、Google Play Console にアプリが必要です。Google Play Console でアプリを作成し、以前に作成した署名付き App Bundle をアップロードします。

アプリを作成する

アプリを作成するには:

  1. デベロッパー アカウントを使用して Google Play Console にログインします。
  2. [アプリを作成] をクリックします。[アプリを作成] ページが開きます。
  3. アプリ名を入力し、デフォルトの言語やアプリ関連のその他の詳細を選択します。
  4. [アプリを作成] をクリックします。これにより、Google Play Console にアプリが作成されます。

これで、サンプルアプリの署名済み App Bundle をアップロードできるようになりました。

署名済みの App Bundle をアップロードする

  1. 署名済みの App Bundle を Google Play Console の内部テストトラックにアップロードします。アップロード後にのみ、Google Play Console で収益化関連の機能を設定できます。
    1. [テストとリリース] > [テスト] > [内部リリース] > [新しいリリースを作成] をクリックします。
    2. リリース名を入力し、署名済み APK ファイルをアップロードします。
    3. [次へ]、[保存して公開] の順にクリックします。

これで、1 回限りのアイテムを作成できます。

1 回限りのアイテムの作成

次に、ユーザーに購入してほしい 1 回限りの商品を作成します。

  1. Google Play Console でサンプルアプリを開き、[Google Play で収益化] > [商品] > [1 回限りの商品] に移動します。
  2. [1 回限りのアイテムを作成] をクリックします。
  3. 次のアイテムの詳細情報を入力します。
    • アイテム ID: 一意の ID を入力します。例: upcoming_movie_1
    • (省略可)タグ: 関連するタグを追加します。
    • 名前: 商品名を入力します。例: Product Movie
    • 説明: 商品の説明を入力します。例: Product Description
    • (省略可)アイコン画像を追加する: 商品を表すアイコンをアップロードします。
    注: この Codelab では、[税金、コンプライアンス、プログラム] セクションの設定はスキップできます。
  4. [次へ] をクリックします。
  5. 購入オプションを追加し、地域別の提供状況を設定します。1 回限りのアイテムには、利用資格の付与方法、価格、地域別の提供状況を定義する購入オプションが少なくとも 1 つ必要です。この Codelab では、商品の標準の [購入] オプションを追加します。[購入オプション] セクションに以下の情報を入力します。
    • 購入オプション ID: 一意の ID を入力します。例: buy-movie
    • 購入タイプ: [購入] を選択します。
    • (省略可)タグ: この購入オプションに固有のタグを追加します。
    • (省略可)[詳細オプション] をクリックして、詳細オプションを構成します。この Codelab では、詳細オプションの構成はスキップできます。
  6. 次に、購入オプションの地域別の提供状況と価格を設定する必要があります。地域別の提供状況では、アイテムを利用できる地域を指定します。アプリがまだ公開されていない地域を含めることもできます。購入オプションは、デフォルトではすべての地域で利用できます。[公開設定と価格] セクションで、[公開設定とアクセス権を編集] をクリックします。
    1. [利用不可に設定] を選択します。
    すべてのリージョンが自動的に選択され、[利用可能] に設定されていることに注意してください。
    1. United States の国のみ選択を解除し、[利用不可に設定] をクリックします。これで、1 回限りのアイテムは United States でのみ利用できるようになります。
    2. [すべての地域] プルダウンで、[利用可能な国と地域] を選択します。United States のみが表示されます。
    3. [価格] アイコンをクリックします。価格を設定するダイアログが表示されます。
    4. 「10 USD」と入力して、[保存] をクリックします。
  7. [下書きとして保存] をクリックします。

: 購入オプションはまだ有効にしないでください。予約購入特典を設定した後で有効にします。これは、地域別の提供状況が設定されている有効な購入オプションに予約購入特典を追加できないためです。

予約購入特典を追加する

次に、先ほど作成した購入オプションの予約購入特典を追加します。予約購入特典を設定すると、ユーザーがアイテムの正式リリース前に購入できるようになります。予約購入特典は、購入オプションで [購入] を選択した場合のみ設定でき、地域内の新しいアイテムにのみ設定できます。

予約購入特典を追加するには、次の 2 つの手順を行います。

  1. 予約購入特典の購入オプションを準備します。
  2. 購入オプションの予約購入特典を追加します。

予約購入特典の購入オプションを準備する

  1. Google Play Console でサンプルアプリを開き、[Google Play で収益化] > [商品] > [1 回限りの商品] に移動します。
  2. [1 回限りのアイテム] ページで、アイテムの右矢印(upcoming_movie_1)をクリックします。[1 回限りのアイテムを編集] ページが開きます。
  3. 先ほど作成した buy-movie 購入オプションの右矢印をクリックします。[購入オプションの編集] ページが開きます。
  4. [提供状況とアクセス方法を編集] をクリックし、[利用可能に設定して予約購入を許可] を選択します。
  5. [すべての地域] プルダウンから、[利用可能な国と地域] を選択します。以前に構成した United States のみが表示されます。
  6. 国を選択し、[予約購入の場合にのみ対象として設定] をクリックします。
  7. [保存] をクリックします。

購入オプションに予約購入特典はまだ追加されていません。次のステップは、予約購入特典を追加することです。

予約購入特典を追加する

  1. Google Play Console でサンプルアプリを開き、[Google Play で収益化] > [商品] > [1 回限りの商品] に移動します。
  2. [1 回限りのアイテム] ページで、アイテム(upcoming_movie_1)の [特典を追加] > [予約購入] をクリックします。[予約購入の追加] ページが開きます。
  3. 予約販売の詳細を入力します。
    • 予約注文 ID:preorder-offer-1」と入力します。
    • (省略可)割引を追加する: [なし]、[割合]、[割引額] のいずれかを選択できます。この Codelab では、[なし] を選択します。
    • (省略可)タグ: 関連するタグを追加します。
    • 開始日時: 3 日以上先の日付を設定します。
    • 終了日時: 開始日から 24 時間以上後の日時を設定します。
    • 予約購入後の提供状況: 予約購入期間後すぐに商品を提供するか、指定した日時に商品を提供するかを選択します。
    • (省略可)安値価格保証: 予約購入時の価格とリリース時の価格のうち、いずれか安い方の価格をユーザーに請求する場合は、このオプションを選択します。これは、早期購入者にとって大きなインセンティブになります。
  4. [保存] をクリックします。
  5. 1 回限りのアイテム(upcoming_movie_1)の [1 回限りのアイテムを編集] ページを開きます。
  6. 購入オプション(buy-movie)の [有効にする] をクリックします。
  7. 購入オプションの予約購入特典(preorder-offer-1)の [有効にする] をクリックします。これにより、予約購入特典が有効になり、予約購入の詳細で以前に設定した日に公開されます。

予約購入特典の作成動画

次の動画は、前述の予約購入特典の作成手順を示しています。

4. PBL と統合する

アプリを Play Billing Library(PBL)と統合する手順は次のとおりです。

  1. サンプルアプリに Play Billing Library の依存関係を追加します。
    dependencies {
    val billing_version = "8.1.0"
    
    implementation("com.android.billingclient:billing-ktx:$billing_version")
    }
    
  2. BillingClient を初期化します。BillingClient は、アプリに存在し、Google Play Billing Library と通信するクライアント SDK です。次のコード スニペットは、課金クライアントを初期化する方法を示しています。
    private BillingClient createBillingClient() {
    return BillingClient.newBuilder(activity)
        .enablePendingPurchases(PendingPurchasesParams.newBuilder().enableOneTimeProducts().build())
        // For one-time products, add a listener to process and acknowledge the purchases. This will notify
        // Google the purchase was processed.
        // For client-only apps, use billingClient.acknowledgePurchase().
        // If you have a secure backend, you must acknowledge purchases on your server using the
        // server-side API.
        // See https://developer.android.com/google/play/billing/security#acknowledge
        // In this sample snippet purchases aren't processed. You must
        // implement your business logic to process and acknowledge the purchases.
        .setListener((billingResult, purchases) -> {})
        .enableAutoServiceReconnection()
        .build();
     }
    
  3. Google Play に接続します。次のコード スニペットは、Google Play に接続する方法を示しています。
    /**
    * Starts the billing connection with Google Play. This method should be called exactly once
    * before any other methods in this class.
    *
    * @param productList The list of products to query for after the connection is established.
    */
    public void startBillingConnection(List<Product> productList) {
        billingClient.startConnection(
            new BillingClientStateListener() {
            @Override
            public void onBillingSetupFinished(BillingResult billingResult) {
                if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                Log.d(TAG, "Billing Client Connection Successful");
                queryProductDetails(productList);
                } else {
                Log.e(TAG, "Billing Client Connection Failed: " + billingResult.getDebugMessage());
                listener.onBillingSetupFailed(billingResult); // Propagate the error to the listener to show a message to the user.
                }
            }
    
            @Override
            public void onBillingServiceDisconnected() {
                Log.e(TAG, "Billing Client Connection Lost");
                listener.onBillingError("Billing Connection Lost");
            }
            });
    }
    
  4. 1 回限りのアイテムの詳細を取得します。アプリを PBL と統合したら、1 回限りのアイテムの詳細をアプリに取得する必要があります。次のコード スニペットは、アプリで 1 回限りのアイテムの詳細を取得する方法を示しています。
    private void queryProductDetails(List<Product> productList) {
        QueryProductDetailsParams queryProductDetailsParams =
            QueryProductDetailsParams.newBuilder().setProductList(productList).build();
    
        billingClient.queryProductDetailsAsync(
            queryProductDetailsParams,
            new ProductDetailsResponseListener() {
            @Override
            public void onProductDetailsResponse(
                BillingResult billingResult, QueryProductDetailsResult productDetailsResponse) {
                if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                List<ProductDetails> productDetailsList =
                    productDetailsResponse.getProductDetailsList();
                    listener.onProductDetailsResponse(productDetailsList);
                } else {
                Log.e(TAG, "QueryProductDetailsAsync Failed: " + billingResult.getDebugMessage());
                listener.onBillingError("Query Products Failed: " + billingResult.getResponseCode());
                }
            }
            });
    }
    
    ProductDetails で 1 回限りのアイテム(この例では upcoming_movie_1)を取得すると、次のようなレスポンスが返されます。
    {
        "productId": "upcoming_movie_1",
        "type": "inapp",
        "title": "Purrfect Mayhem: The Final Playback (Movies All Day | Play Samples)",
        "name": "Purrfect Mayhem: The Final Playback",
        "description": "Yolo and Thorne must reach the original broadcasting site to initiate the \"Final Playback\" and save the timeline. Follow them through their race against the Clockinators.",
        "skuDetailsToken": "<---skuDetailsToken--->",
        "oneTimePurchaseOfferDetails": {},
        "oneTimePurchaseOfferDetailsList": [
            {
                "priceAmountMicros": 8500000,
                "priceCurrencyCode": "USD",
                "formattedPrice": "$8.50",
                "offerIdToken": "<---offerIdToken--->",
                "offerId": "preorder",
                "purchaseOptionId": "buy-option",
                "offerTags": [],
                "validTimeWindow": {
                    "startTimeMillis": 1756771200000,
                    "endTimeMillis": 1785542400000
                },
                "preorderDetails": {
                    "preorderReleaseTimeMillis": 1785542400000,
                    "preorderPresaleEndTimeMillis": 1785542400000
                }
            }
        ]
    }
    
    予約購入特典の詳細は oneTimePurchaseOfferDetailsList で確認できます。このリストには、Google Play Console で予約購入特典が設定された購入オプション(buy-option)が 1 つ含まれています。各購入オプションは、offerIdToken で一意に識別できます。
  5. 予約購入特典の詳細とともに特典トークンを取得します。ステップ 6 で請求フローを開始するには、特典トークンが必要です。
    @Override
    public void onProductDetailsResponse(List<ProductDetails> productDetailsList) {
    
    if (productDetailsList != null && !productDetailsList.isEmpty()) {
    
    // Process productDetailsList returned by QueryProductDetailsResult
    for (ProductDetails productDetails : productDetailsResult.getProductDetailsList()) {
      for (OneTimePurchaseOfferDetails oneTimePurchaseOfferDetails :
          productDetails.getOneTimePurchaseOfferDetailsList()) {
        // Checks if the offer is a preorder offer.
        if (oneTimePurchaseOfferDetails.getPreorderDetails() != null) {
          // Process the returned PreorderDetails
          OneTimePurchaseOfferDetails.PreorderDetails preorderDetails =
              oneTimePurchaseOfferDetails.getPreorderDetails();
          // Get preorder release time in millis.
          long preorderReleaseTimeMillis = preorderDetails.getPreorderReleaseTimeMillis();
          // Get preorder presale end time in millis.
          long preorderPresaleEndTimeMillis = preorderDetails.getPreorderPresaleEndTimeMillis();
          // Get offer ID
            String offerId = oneTimePurchaseOfferDetails.getOfferId();
          // Get the associated purchase option ID
          if (oneTimePurchaseOfferDetails.getPurchaseOptionId() != null) {
            String purchaseOptionId = oneTimePurchaseOfferDetails.getPurchaseOptionId();
          }
        }
      }
      }
      } else {
            Log.e(TAG, "No product details found for " + productId);
        }
    }
    
  6. 請求フローを開始します。
    /**
     * Launches the billing flow for the product with the given offer token.
    *
    * @param activity The activity instance from which the billing flow will be launched.
    * @param productDetails The product details of the product to purchase.
    * @param offerToken The offer token of the product to purchase.
    * @return The result of the billing flow.
    */
    public void launchPurchase(Activity activity, ProductDetails productDetails, String offerToken) {
        ImmutableList<BillingFlowParams.ProductDetailsParams> productDetailsParamsList =
            ImmutableList.of(
                BillingFlowParams.ProductDetailsParams.newBuilder()
                    .setProductDetails(productDetails)
                    .setOfferToken(offerToken)
                    .build());
        BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
            .setProductDetailsParamsList(productDetailsParamsList)
            .build();
        billingClient.launchBillingFlow(activity, billingFlowParams);
    }
    

5. テスト購入オプション

1 回限りのアイテムを公開アプリで利用可能にする前に、ライセンス テスターと Play Billing Lab を使用して PBL 統合をテストできます。

Play Billing Lab を使用して購入オプションをテストする方法については、地域別の商品価格設定で新しい市場を開拓する Codelab をご覧ください。

6. 次のステップ

リファレンス ドキュメント

7. 完了

おめでとうございます!Google Play Console で 1 回限りのアイテムの予約購入特典を正常に作成しました。これで、Google Play の 1 回限りの購入用の柔軟なアイテム カタログについて、より深く理解できたはずです。

アンケート

この Codelab に関するフィードバックをお待ちしております。アンケートへのご協力をお願いいたします。