地域別の商品価格設定で新しい市場を開拓する

1. はじめに

この Codelab では、1 回限りのアイテムの作成、購入オプションの定義、地域別の価格の設定、1 回限りのアイテムの購入フローのテストに焦点を当てます。

対象

この Codelab は、Google Play Console を使用して 1 回限りのアイテムのカタログを管理したい Android アプリ デベロッパーを対象としています。

学習内容

  • 1 回限りのアイテム オブジェクト モデル
  • Google Play Console を使用して 1 回限りのアイテムのカタログを管理する方法。
  • 1 回限りのアイテムの詳細をさまざまな言語に無料で翻訳する方法。
  • 1 回限りのアイテムの地域別の在庫状況と価格を設定する方法。
  • Play Billing Library API を使用して 1 回限りのアイテムの詳細をクエリする方法。
  • Play Billing Lab を使用して 1 回限りのアイテムをテストする方法。

必要なもの

2. 1 回限りのアイテムの初回リリース

1 回限りのアイテムのオブジェクト モデルにより、アイテムの販売方法がさらに柔軟になり、管理の煩雑さが軽減されます。このオブジェクト モデルでは、販売するアイテムとその販売方法を別々に設定できるため、利用資格が同じユーザーに対して複数の価格を設定したり、ユーザーによってマーケティング方法を変えたりできます。オブジェクト モデルには 3 つの階層レベルがあります。

  • 1 回限りのアイテム - ユーザーが購入するアイテムを定義します。
  • 購入オプション - ユーザーに利用資格を付与する方法、価格、アイテムを利用できる地域を定義します。1 つのアイテムに複数の購入オプションを設定できるため、たとえば地域ごとに異なる価格を設定することも可能です。
  • 特典 - 特典は、割引や予約購入のモデル化に使用でき、関連付けられている購入オプションの価格に影響する可能性があります。1 つの購入オプションに複数の特典を設定できます。

次の図は、1 回限りのプロダクト オブジェクト モデルを示しています。

codelab-otp-model.png 図 1: 1 回限りのオブジェクト モデル。

詳しくは、1 回限りのアイテムの概要をご覧ください。

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

この 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 にアップロードすることです。

4. Google Play Console で 1 回限りのアイテムを作成する

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

これで、1 回限りのアイテムを作成できるようになりました。

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

1 回限りのアイテムを作成する手順は次のとおりです。

  1. Google Play Console の左側のナビゲーション メニューで、[Google Play で収益化する] > [アイテム] > [1 回限りのアイテム] に移動します。
  2. [1 回限りのアイテムを作成] をクリックします。
  3. 次のアイテムの詳細情報を入力します。
    • アイテム ID: 一意の ID を入力します。例: trending_movie_1
    • (省略可)タグ: 関連性の高いタグを追加します。
    • 名前: 商品名を入力します。例: Product Movie
    • 説明: 商品の説明を入力します。例: Product Description
    商品名と説明の手動翻訳
    デフォルトでは、商品名と説明は 英語(米国) - en-US 言語で表示されます。他の言語の名前と説明を手動で入力することもできます。詳細を入力するには、[翻訳を管理] をクリックし、翻訳テキストを入力する言語を選択して、[適用] をクリックします。次の画像は、[翻訳を管理] オプションを示しています。manage-translations.png図 2: 翻訳を管理。

    選択した言語が言語のプルダウンに表示されます。各言語を選択し、選択した言語で対応する名前と説明を入力します。商品名と商品説明を無料で自動翻訳することもできます。詳しくは、この Codelab の1 回限りのアイテムを翻訳するセクションをご覧ください。

    : この Codelab では、[アイコン] フィールドと [税金、コンプライアンス、プログラム] セクションの構成はスキップできます。
  4. [次へ] をクリックします。
  5. 購入オプションを追加して、地域別の提供状況を設定します。1 回限りのアイテムには、利用資格の付与方法、価格、地域別の提供状況を定義する購入オプションが少なくとも 1 つ必要です。この Codelab では、商品の標準の [購入] オプションを追加します。

    [購入オプション] セクションに以下の情報を入力します。
    • 購入オプション ID: 一意の ID を入力します。例: buy-movie
    • 購入タイプ: [購入] を選択します。
    • (省略可)タグ: この購入オプションに固有のタグを追加します。
    • (省略可)[詳細オプション] をクリックして、詳細オプションを構成します。この Codelab では、詳細オプションの構成はスキップできます。
  6. 次に、購入オプションの地域別の提供状況と価格を設定する必要があります。地域別の提供状況では、アイテムを利用できる地域を指定します。アプリがまだ公開されていない地域を含めることもできます。購入オプションは、デフォルトではすべての地域で利用できます。

    [公開設定と価格] セクションで、[公開設定とアクセス方法を編集 > 利用不可に設定] をクリックします。デフォルトでは、すべてのリージョンが [使用可能] に設定されています。
    1. FranceSpainUnited States 以外のすべての国を選択し、[利用不可に設定] をクリックします。
    2. [すべての地域] プルダウンから、[利用可能な国と地域] を選択します。前のステップで選択した国のみが表示されます。
    3. 利用可能な国ごとに、[価格] 列の編集アイコンをクリックします。価格を編集するダイアログが表示されます。次の価格を入力して保存します。
      • France に「10 EUR」と入力します。
      • Spain に 8 EUR と入力します。
      • United States に 13 USD と入力します。
  7. [Activate] をクリックします。これにより、1 回限りのアイテムが購入オプションとして「購入」で利用可能になります。

: 地域別価格の通貨は、ユーザーの Google Play の国 / 地域の設定に基づいて表示されます。たとえば、ユーザーの Play の国がフランスに設定されている場合、1 回限りのアイテムの価格はユーロで表示されます。

1 回限りのアイテムの作成に関する動画

次の動画では、前述の 1 回限りの商品作成手順を確認できます。

「レンタル」購入オプションを追加する

次に、作成済みの 1 回限りのアイテムにレンタル購入オプションを追加します。

  1. Google Play Console の左側のナビゲーション メニューで、[Google Play で収益化する] > [アイテム] > [1 回限りのアイテム] に移動します。
  2. 前の手順で作成した trending_movie_1 プロダクト ID のプロダクトの右矢印をクリックします。
  3. [購入オプションを追加] をクリックします。
  4. [購入オプション] セクションに以下の情報を入力します。
    • 購入オプション ID:rent-movie」と入力します。
    • 購入タイプ: [レンタル] を選択します。
    • レンタル期間: 48 時間を選択します。
    • レンタル開始期間: 24 時間を選択します。
    • (省略可)タグ: この購入オプションに固有のタグを追加します。
    • (省略可)[詳細オプション] をクリックして、詳細オプションを構成します。この Codelab では、詳細オプションの構成はスキップできます。
  5. 次に、購入オプションと同様に、レンタル購入オプションの地域別の提供状況を設定します。前のセクションの手順 6 と 7 をご覧ください。地域別の価格を設定する際は、レンタル用に別の価格を設定します。次に例を示します。
    • France - 5 ユーロ
    • Spain - 4 ユーロ
    • United States - 7 米ドル。

5. 1 回限りのアイテムの詳細を翻訳する

Google Play Console で利用できる機械翻訳機能を使用すると、商品名と説明を無料で翻訳できます。

タイトルと説明を翻訳するには、次の操作を行います。

  1. Google Play Console の左側のナビゲーション メニューで、[ユーザーを増やす] > [翻訳] > [ストアとアプリ内アイテム] に移動します。
  2. [注文する] をクリックします。
  3. [Machine translation at no cost] オプションを選択し、[Next] をクリックします。
  4. [Translate to] 言語で [French - fr-FR] と [Spanish -es-ES] を選択し、[Next] をクリックします。
  5. [1 回限りのアイテムと定期購入] を選択し、[翻訳して翻訳を表示] をクリックします。免責条項のバナーが表示されます。免責条項に同意します。
  6. 翻訳された言語のリストが表示されます。言語の [確認して適用] をクリックします。テキストを確認し、[すべての翻訳を適用] をクリックします。翻訳対象として選択したすべての言語について、この手順を繰り返します。

翻訳後、Google Play Console で翻訳されたテキストを編集できます。翻訳されたテキストを編集するには:

  1. [1 回限りのアイテム > [1 回限りのアイテム] > [1 回限りのアイテムを編集] > [1 回限りのアイテムの詳細を編集]] ページを開きます。
  2. 言語プルダウンから必要な言語を選択します。これにより、選択した言語でテキストが表示されます。次の図は、翻訳されたテキストを編集する言語の選択を示しています。

    edit-translations.png 図 3: 翻訳されたテキストを編集する。
  3. 必要に応じてテキストを編集し、[変更を保存] をクリックします。

翻訳されたテキストは、ユーザーのスマートフォンの言語設定に基づいてユーザーに表示されます。たとえば、ユーザーのスマートフォンの言語がフランス語に設定されている場合、1 回限りのアイテムのタイトルと説明はフランス語で表示されます。次のサンプル画像は、さまざまな言語で翻訳されたテキストがどのように表示されるかを示しています。

post-translation.png図 4: アプリ内の翻訳されたテキスト。

変換構成の動画

次の動画は、前述の翻訳構成の手順を示しています。

6. PBL と統合する

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

  1. サンプルアプリに Play Billing Library の依存関係を追加します。
    dependencies {
    val billing_version = "8.0.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 回限りのアイテム(この例では trending_movie_1)を取得すると、次のようなレスポンスが返されます。
    {
        "productId": "trending_movie_1",
        "type": "inapp",
        "title": "Purrfect Mayhem: The Rewind Protocol (Movies All Day | Play Samples)",
        "name": "Purrfect Mayhem: The Rewind Protocol",
        "description": "Dr. Arid Thorne and a smart tiger named Yolo find a mysterious tape. It's a \"Rewind Protocol\" to fix time. A shadowy group, the Clockinator, hunts them to seize the tape's power.",
        "skuDetailsToken": "<---skuDetailsToken--->",
        "oneTimePurchaseOfferDetails": {},
        "oneTimePurchaseOfferDetailsList": [
            {
                "priceAmountMicros": 13000000,
                "priceCurrencyCode": "USD",
                "formattedPrice": "$13.00",
                "offerIdToken": "<---buy offerIdToken --->",
                "purchaseOptionId": "buy-option",
                "offerTags": [
                    "adventure",
                    "mystery"
                ]
            },
            {
                "priceAmountMicros": 7000000,
                "priceCurrencyCode": "USD",
                "formattedPrice": "$7.00",
                "offerIdToken": "<---rent offerIdToken--->",
                "purchaseOptionId": "rent-option",
                "offerTags": [
                    "adventure",
                    "mystery"
                ],
                "rentalDetails": {
                    "rentalPeriod": "P30D",
                    "rentalExpirationPeriod": "PT24H"
                }
            }
        ]
    }
    
    oneTimePurchaseOfferDetailsList で購入とレンタルの購入オプションが利用可能になっていることに注目してください。このリストには、Google Play Console で構成された 2 つの購入オプション(buy-optionrent-option)があります。各購入オプションは、offerIdToken で一意に識別できます。
  5. レンタルと購入の特典の特典トークンを取得します。ステップ 6 で請求フローを開始するには、特典トークンが必要です。
    @Override
    public void onProductDetailsResponse(List<ProductDetails> productDetailsList) {
    
        if (productDetailsList != null && !productDetailsList.isEmpty()) {
    
            // Iterate over all details of the queried product in step 4.
            for (ProductDetails productDetails : productDetailsList) {
    
                // Get the list of all the offers associated with the product.
                List<ProductDetails.OneTimePurchaseOfferDetails> offerDetailsList =
                        productDetails.getOneTimePurchaseOfferDetailsList();
    
                // Iterate over the offer details
                for (ProductDetails.OneTimePurchaseOfferDetails offerDetails : offerDetailsList) {
    
                    // For a Rent purchase option, the
                    // offerDetails.getRentalDetails() method returns
                    // the rent information. If this information is present,
                    // the offer corresponds to a Rent purchsae option.
                    if (offerDetails.getRentalDetails() != null) {
                        rentFormattedPrice = offerDetails.getFormattedPrice();
    
                        // Get the offerIdToken for the Rent purchase option
                        rentOfferToken = offerDetails.getOfferToken();
                        rentMovieTags = offerDetails.getOfferTags();
                    }
                    // If the offerDetails.getRentalDetails() returns
                    // null, the offer corresponds to a Buy purchsae option.
                    else {
                        buyFormattedPrice = offerDetails.getFormattedPrice();
    
                        // Get the offerIdToken for the Buy purchase option
                        buyOfferToken = offerDetails.getOfferToken();
                        buyMovieTags = offerDetails.getOfferTags();
                    }
                }
                updateUIButtons();
                return;
    
            }
        } 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);
    }
    

ヒント: リアルタイム デベロッパー通知(RTDN)を設定して、再購入キャンペーンやその他の購入ライフサイクル管理戦略を実装することもできます。RTDN を設定し、正確なトラッキングと利用資格で通知を処理する方法については、Google Play の課金統合を最大限に活用する Codelab をご覧になることをおすすめします。

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

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

このコースでは、アプリが一部の地域でのみ利用可能で、地域ごとに価格が異なる場合に、価格のローカライズと利用可能性をテストする方法について説明します。

前提条件

購入オプションの地域別価格をテストする

購入オプションの地域別の価格をテストする手順は次のとおりです。

  1. Play Billing Lab アプリを開き、ライセンス テスターとしてログインします。
  2. [構成設定] で [編集] をクリックし、国 France を選択して、[適用] をクリックします。ここでは、アプリに表示される通貨を決定する Google Play の国を選択します。
  3. サンプルアプリを閉じて再度開きます。France の購入とレンタルの通貨がユーロで表示されるようになります。

別の国でテストするには、ステップ 2 で Spain を選択してから、ステップ 3 を実行します。

Play Billing Lab のテスト動画

次の動画は、サンプルアプリを使用して地域別価格のテストを行う手順を示しています。

8. 次のステップ

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

9. 完了

おめでとうございます!Google Play Console を操作して、新しい 1 回限りのアイテムを作成し、購入オプションを設定し、Play Billing Lab を使用して購入フローをテストしました。これで、Google Play の 1 回限りの購入用の柔軟なアイテム カタログについて、より深く理解できたはずです。

アンケート

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