この Codelab について
1. 概要
Google Play の Play Billing Library 統合 Codelab で、収益源を最適化し、安心してアプリをリリースしましょう。この Codelab では、信頼性の高い購入処理の設定、テスト、実装について説明します。これにより、収益化目標を達成し、よりシームレスなユーザー エクスペリエンスを提供できます。
アプリやゲームのサブスクリプションと 1 回限りのアイテムについて、リアルタイム デベロッパー通知(RTDN)と Play Billing Lab の設定をサポートします。定期購入の解約を減らす方法、不正行為や不正使用から保護する方法、エッジケースをテストする方法、潜在的な問題をシミュレート、再現、対処する方法、ユーザーに影響を与えることなく特典や料金の変更をテストする方法について学びます。
最後まで学習すると、ユーザーの再獲得戦略を実装し、統合に関する課題を迅速に解決し、費用対効果を高め、プレミアム エクスペリエンスを提供して、アプリとアップデートを安心してリリースできるようになります。
前提条件
- 基本的な Google Play Billing Library の統合に関する知識
- Android アプリ開発(Java)に関する知識
学習内容
- 購入ライフサイクルを適切に管理し、購入コンバージョンと顧客維持率を高める手法で成長を最適化する方法
- Google Cloud Pub/Sub を使用してリアルタイム デベロッパー通知(RTDN)を設定する方法。この通知は、再獲得キャンペーンやその他のライフサイクル管理戦略の実装に活用できます。
- バックエンド サーバーでレシーバーを設定して、正確なトラッキングと利用資格で通知を安全に処理し、意図しない払い戻しや不正行為、不正使用のリスクを軽減する方法
- Play Billing Lab を使用して統合をテストし、エラーをシミュレートして、開発コストを削減しながらユーザー エクスペリエンスを向上させる方法
必要なもの
- Google Play Console でアプリの Play デベロッパー アカウントにアクセスできる
- Google Play Developer API が有効になっている Google Cloud Platform プロジェクトへのアクセス権
- Android アプリのアカウントと利用資格を処理するバックエンド サーバー
- Google Play Console でアプリに登録されているライセンス テスター
- テストデバイスにインストールされている Play Billing Lab
2. 定期購入と 1 回だけの購入の収益化戦略
アプリでデジタル商品を販売する場合、収益化戦略を成功させるには、1 回限りの購入と定期購入の両方において、ユーザー エクスペリエンス全体を考慮する必要があります。シームレスなエクスペリエンスにより、購入意欲を高め、解約を減らすことができます。
1 回限りの購入または定期購入の一般的な購入フローには、複数のステージが含まれます。
- ユーザーが購入する商品を閲覧しています。
- 購入フローを起動して、ユーザーが購入と支払いを完了できるようにします。
- 購入の完了をサーバーに通知する
- サーバーで購入を確認します。
- ユーザーにコンテンツを提供します。
- コンテンツの配信を承認します。消費型アイテムの場合は、適切なタイミングで購入アイテムを消費し、ユーザーがアイテムを再購入できるようにします。
アプリ内統合を使用すると、購入フローを開始して、ユーザー エクスペリエンスを管理できますが、ユーザーが購入している利用資格についてバックエンドで最新のステータスに保つことが重要となります。購入のトラッキングと、クロス プラットフォームでの利用資格など、ユーザー エクスペリエンスの別の側面の管理において、これは重要です。
リアルタイム デベロッパー通知(RTDN)は、購入ライフサイクルのさまざまな段階を認識するのに最適な方法です。リアルタイムのパフォーマンス トラッキング ツールとして、また定期購入者の再獲得戦略を可能にするツールとして効果的に使用できます。
たとえば、ユーザーが新しいアイテムを購入したばかりの場合や、支払いを行わなかったために定期購入が猶予期間に入った場合などです。適切な RTDN を使用すると、ユーザーのステータスが変更されたことをほぼリアルタイムで認識し、それに応じて対応できます。たとえば、ユーザーが購入したアイテムへのエンゲージメントをさらに高めたり、定期購入を継続するために支払い情報を更新するようリマインダー メールを送信したりできます。
RTDN は、ユーザーのクライアントに問題が発生した場合でも購入を管理できるように、サーバーサイドのコントロールを追加するのにも適しています。ユーザーが購入に成功して Google から確認通知を受け取ったが、デバイスとアプリが購入リスナーを通じて購入通知を受け取る前にネットワーク接続を失った場合。RTDN を使用すると、サーバーを介して独立した通知が届きます。これにより、クライアントの問題に関係なく購入を認識し、ユーザーに利用資格を付与できるため、購入プロセスの信頼性が確保されます。
現在サポートされているすべての種類の RTDN について詳しくは、こちらをご覧ください。各タイプの RTDN は、個別の購入ステータスを通知します。ユースケースで必要に応じて適切に処理されるように、対応する処理メカニズムを実装することが重要です。この Codelab では、ユーザーがアプリで購入を正常に完了したときに、安全なバックエンド サーバーで RTDN メッセージを処理する例について説明します。メッセージの受信、購入の検証、正しいユーザーへの利用資格の付与などについて説明します。次に、アプリの RTDN を構成する方法について説明します。
3. リアルタイム デベロッパー通知(RTDN)を構成する
リアルタイム デベロッパー通知(RTDN)は、Google Cloud Pub/Sub を利用して、購入ステータスの変更にすぐに対応できるようにします。Cloud Pub/Sub は、独立したアプリケーション間でメッセージを送受信するために使用できるフルマネージドのリアルタイム メッセージ サービスです。Google Play は、Cloud Pub/Sub を使用して、デベロッパーがサブスクライブしているトピックに関するプッシュ通知をパブリッシュします。
RTDN を有効にするには、まずご自身の Google Cloud Platform(GCP)プロジェクトを使用して Cloud Pub/Sub を設定し、次にアプリへの通知を有効にする必要があります。GCP と Cloud Pub/Sub の使用経験がない場合は、クイックスタート ガイドをご覧ください。
トピックの作成
通知を受信するには、Google Play による通知のパブリッシュ先となるトピックを作成する必要があります。トピックを作成するには、トピックを作成するの手順に沿って操作します。
Pub/Sub サブスクリプションを作成する
トピックにパブリッシュされたメッセージを受信するには、そのトピックに対する Pub/Sub サブスクリプションを作成する必要があります。Pub/Sub サブスクリプションを作成する手順は次のとおりです。
- Cloud Pub/Sub サブスクライバー ガイドで、サブスクリプションをプッシュ サブスクリプションまたはプル サブスクリプションとして構成する方法を確認します。この Codelab では、安全なバックエンド サーバーが Cloud Pub/Sub サーバーへのリクエストを開始してメッセージを取得する必要がある pull サブスクリプションについて説明します。
- サブスクリプションの追加の手順に沿って、サブスクリプションを作成します。
トピックに関する公開権限を付与する
Cloud Pub/Sub では、トピックに通知をパブリッシュする権限を Google Play に付与することが必要です。
- Google Cloud コンソールを開きます。
- プロジェクトを選択し、検索バーで「Pub/Sub」を検索して、Pub/Sub 構成ページに移動します。
- トピックを見つけて権限の設定を開きます。
- [プリンシパルを追加] をクリックしてサービス アカウント
google-play-developer-notifications@system.gserviceaccount.com
を追加し、Pub/Sub パブリッシャーのロールを付与します。 - [保存] をクリックして、トピックの設定を完了します。
アプリで RTDN を有効にする
リアルタイム デベロッパー通知(RTDN)を設定して、Play 請求サービスの統合を大幅に強化する方法を学びます。パーソナライズされたメッセージにより購入の信頼性を高め、不正行為や不正使用を防ぐことで、全体的な ROI を高めることができます。
RTDN は、定期購入の更新、新規購入、お支払いに関する問題などの重要なイベントについて、Google Play から直接サーバー間更新を即時に提供します。バックエンド システムがユーザーの利用資格の実際のステータスと自動的に同期されるため、クライアントサイドの制限を超えて、迅速かつ適切に対応できます。
アプリでリアルタイム デベロッパー通知を有効にする方法は次のとおりです。
- Google Play Console を開きます。
- アプリを選択
- [Google Play で収益化] > [収益化のセットアップ] に移動します。
- [リアルタイム デベロッパー通知] までスクロールします。
- [リアルタイム通知を有効にする] チェックボックスをオンにします。
- [トピック名] に、先ほど設定した Cloud Pub/Sub の完全なトピック名を入力します。トピック名は projects/{project_id}/topics/{topic_name} の形式にする必要があります。ここで、project_id はプロジェクトの一意の ID、topic_name は先ほど作成したトピックの名前です。
- [テスト メッセージを送信] をクリックしてテスト メッセージを送信します。テスト公開を実行すると、すべてが適切に設定および構成されていることを確認するのに役立ちます。テスト公開が成功すると、成功したことを示すメッセージが表示されます。このトピックにサブスクリプションをアタッチしている場合は、テスト メッセージを受信します。pull サブスクリプションの場合は、Cloud コンソールでサブスクリプションに移動し、[メッセージを表示] をクリックして、メッセージの pull に進みます。Cloud Pub/Sub によって繰り返し配信されるのを避けるため、pull したメッセージの確認応答が必要です。push サブスクリプションの場合、テスト メッセージが push エンドポイントに配信されているかどうかを確認します。成功のレスポンス コードはメッセージの確認応答として機能します。パブリッシュが失敗すると、エラーが表示されます。トピック名が正しいこと、トピックに対する Pub/Sub パブリッシャー アクセス権が
google-play-developer-notifications@system.gserviceaccount.com
サービス アカウントに付与されていることを確認してください。 - 受け取る通知の種類を選択します。
- 定期購入と無効になったすべての購入に関する通知を受け取る - 定期購入と無効になった購入に関連するリアルタイム デベロッパー通知を受け取ります。1 回限りのアイテムの購入に関する通知は届きません。
- 定期購入と 1 回限りのアイテムに関するすべての通知を受け取る - 定期購入と取り消し済みの購入のすべてのイベントに関する通知を受け取ります。また、
ONE_TIME_PRODUCT_PURCHASED
やONE_TIME_PRODUCT_CANCELED
などの 1 回限りのアイテム購入イベントも届きます。これらの購入イベントの詳細については、1 回だけの購入のライフサイクルをご覧ください。
- [変更を保存] をクリックします。
これで、アプリのリアルタイム デベロッパー通知が完了しました。これにより、ユーザーの離脱を防ぐメッセージ送信や、不正行為や不正使用などの一般的な課題に対処するためのツールが提供されます。次のセクションでは、Cloud Pub/Sub トピックに送信されたメッセージを消費するサブスクライバーを安全なバックエンド サーバーに作成します。
4. 通知を受け取る
アプリで最適なユーザー エクスペリエンスを実現するには、バックエンド サーバーで購入ステータスを最新の状態に保つことが重要です。たとえば、ユーザーがアプリ内で支払いを行って購入を完了した場合、できるだけ早くコンテンツをアカウントに配信する必要があります。
そのためには、購入の完了を適切なタイミングで検出して処理する必要があります。Play Billing Library には、アプリで購入を検出する複数の方法が用意されています。購入が完了したことを検出したら、アプリはバックエンド サーバーに通知して購入を確認します。その後、正しいユーザーにコンテンツを付与し、購入が処理されたことを Google に通知します。ただし、さまざまな理由でアプリが購入を適時に検出できなかった可能性があります。たとえば、ユーザーが購入に成功して Google から確認通知を受け取ったが、デバイスが Play Billing Library インターフェースを通じて購入通知を受け取る前にネットワーク接続を失った場合。RTDN には、ユーザーのクライアントに問題がある場合でも購入を管理できるように、追加のサーバーサイド コントロールが用意されています。RTDN では、購入ステータスの変更時にサーバーに独立した通知が送信されるため、クライアントの問題に関係なく、2 番目のパスを通じて購入ステータスの変更をほぼ即座に認識でき、購入プロセスの信頼性が高まります。
このセクションでは、Cloud Pub/Sub クライアント ライブラリを使用して、Cloud Pub/Sub トピックに送信されたメッセージを消費するサブスクライバーを作成します。これらのライブラリは、さまざまな言語で利用できます。以降のセクションでは、サブスクライバーに追加して購入を確認する、正しいユーザーに利用資格を付与する、サーバーで購入を承認/使用する処理を行います。この Codelab では Java を使用します。
Cloud Pub/Sub トピックに対して行われた各パブリッシュには、base64 でエンコードされたデータ フィールドが 1 つ含まれます。
{
"message": {
"attributes": {
"key": "value"
},
"data": "eyAidmVyc2lvbiI6IHN0cmluZywgInBhY2thZ2VOYW1lIjogc3RyaW5nLCAiZXZlbnRUaW1lTWlsbGlzIjogbG9uZywgIm9uZVRpbWVQcm9kdWN0Tm90aWZpY2F0aW9uIjogT25lVGltZVByb2R1Y3ROb3RpZmljYXRpb24sICJzdWJzY3JpcHRpb25Ob3RpZmljYXRpb24iOiBTdWJzY3JpcHRpb25Ob3RpZmljYXRpb24sICJ0ZXN0Tm90aWZpY2F0aW9uIjogVGVzdE5vdGlmaWNhdGlvbiB9",
"messageId": "136969346945"
},
"subscription": "projects/myproject/subscriptions/mysubscription"
}
base64 でエンコードされたデータ フィールドをデコードすると、DeveloperNotification
に以下のフィールドがあります。
{
"version": string,
"packageName": string,
"eventTimeMillis": long,
"oneTimeProductNotification": OneTimeProductNotification,
"subscriptionNotification": SubscriptionNotification,
"voidedPurchaseNotification": VoidedPurchaseNotification,
"testNotification": TestNotification
}
詳しくは、リアルタイム デベロッパー通知のリファレンスをご覧ください。
安全なバックエンド サーバーが Pub/Sub メッセージを処理するための NotificationReceiver のサンプルコードを次に示します。Security Command Center で認証を行うには、アプリケーションのデフォルト認証情報を設定します。ローカル開発環境の認証を設定するをご覧ください。
import com.google.cloud.pubsub.v1.AckReplyConsumer;
import com.google.cloud.pubsub.v1.MessageReceiver;
import com.google.cloud.pubsub.v1.Subscriber;
import com.google.pubsub.v1.ProjectSubscriptionName;
import com.google.pubsub.v1.PubsubMessage;
import java.util.Base64;
import org.json.JSONObject;
/** Real-time developer notifications receiver. */
public class NotificationReceiver {
private NotificationReceiver() {}
/*
* Receive notification messages from the subscription.
*
* @param projectId The project ID of your Google Cloud Project.
* @param subscriptionId The subscription ID of the subscriber to the pub/sub topic.
*/
public static void receiveNotificationMessages(String projectId, String subscriptionId) {
ProjectSubscriptionName subscriptionName =
ProjectSubscriptionName.of(projectId, subscriptionId);
try {
Subscriber subscriber =
Subscriber.newBuilder(subscriptionName, new NotificationMessageReceiver()).build();
// Start the subscriber.
subscriber.startAsync().awaitRunning();
subscriber.awaitTerminated();
} catch (IllegalStateException e) {
System.out.println("Subscriber stopped: " + e);
}
}
static class NotificationMessageReceiver implements MessageReceiver {
@Override
public void receiveMessage(PubsubMessage message, AckReplyConsumer consumer) {
// Decode the data into a String from the message data field.
String jsonString = new String(Base64.getDecoder().decode(message.getData().toStringUtf8()));
// Parse the String into a JSON object.
JSONObject messageJson = new JSONObject(jsonString);
// Fetch the value for certain fields.
String version = messageJson.getString("version");
String packageName = messageJson.getString("packageName");
System.out.println("version: " + version);
System.out.println("packageName: " + packageName);
// Validate the purchase and grant the entitlement as needed.
// More details in the following sections.
// ......
// Acknowledge the message to avoid repeated delivery.
consumer.ack();
}
}
}
これで、安全なバックエンド サーバーで Cloud Pub/Sub トピックに送信されたメッセージを消費する通知レシーバーができました。以降のセクションでは、バックエンド サーバーで RTDN メッセージを処理するためのベスト プラクティスについて説明します。
5. アプリの購入フローでユーザー ID を付加する
購入ステータスの更新に関する RTDN メッセージをサーバー側が受信したときに、正しいユーザーにコンテンツを配信するなど、購入を処理するために、どのユーザーが購入したかをサーバー側で把握する必要があります。これは、アプリで購入フローを起動するときに obfuscatedAccountId を使用して、購入したユーザーのユーザー ID を付加することで実現できます。ID の例としては、システム内のユーザーのログインの難読化されたバージョンなどがあります。このパラメータを設定すると、Google が不正行為を検出しやすくなります。また、ユーザーに利用資格を付与するで説明したように、購入が適切なユーザーに帰属するようにすることもできます。
次のコードサンプルは、obfuscatedAccountId を設定して、アプリで購入フローを起動するときにユーザー ID を付加するものです。
// An activity reference from which the billing flow will be launched.
Activity activity = ...;
// A user identifier, e.g. an obfuscated user id in your system.
String obfuscatedAccountId = ...;
ImmutableList<ProductDetailsParams> productDetailsParamsList =
ImmutableList.of(
ProductDetailsParams.newBuilder()
// retrieve a value for "productDetails" by calling queryProductDetailsAsync()
.setProductDetails(productDetails)
// set the offer token to specify the offer to purchase when applicable, e.g., subscription products
// .setOfferToken(offerToken)
.build()
);
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setObfuscatedAccountId(obfuscatedAccountId)
.build();
// Launch the billing flow
BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
次のセクションで説明するように、購入フローで設定されたユーザー ID は購入に含まれ、正しいユーザーに利用資格を付与するために使用できます。
6. 利用権を付与する前に購入を確認する
このセクションでは、安全なバックエンド サーバーで利用権を付与する前に購入を確認するためのベスト プラクティスについて説明します。
ユーザーが 1 回限りのアイテムを購入すると、安全なバックエンド サーバーの Pub/Sub サブスクライバーが Pub/Sub メッセージを受信します。バックエンド サーバーで次の操作を行います。
- Pub/Sub メッセージから
purchaseToken
を解析します。すべての購入ですべてのpurchaseToken
値の記録を保持する必要があります。 - 現在の購入の
purchaseToken
値が以前のどのpurchaseToken
値とも一致しないことを確認します。purchaseToken
はグローバルに一意であるため、この値はデータベースの主キーとして安全に使用できます。 - Google Play Developer API の purchases.products:get エンドポイントを使用して、購入が正当であることを Google に確認します。
- 購入が正当であり、過去に使用されたことがない場合は、アプリ内アイテムや定期購入に対する利用権を安全に付与することができます。
- 購入ステータスが
PURCHASED
の場合にのみ利用資格を付与し、PENDING
の購入を正しく処理してください。詳細については、保留中の取引の処理をご覧ください。
次のコードサンプルは、Google Play Developer API の API クライアントを作成します。これは、後で API 呼び出しを行うために使用します。
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.androidpublisher.AndroidPublisher;
import com.google.api.services.androidpublisher.AndroidPublisherScopes;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Collections;
/** Helper class to initialize the publisher APIs client library. */
public class AndroidPublisherHelper {
/* Your application name */
private static final String APPLICATION_NAME = "YourApplicationName";
/* Load credentials from a JSON key file. Replace with the actual path to your downloaded service
* account key file.
*/
private static final String RESOURCES_CLIENT_SECRETS_JSON =
"/path/to/your/service_account_key.json";
/** Global instance of the JSON factory. */
private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
/* The API client */
private static final AndroidPublisher ANDROID_PUBLISHER = init();
/**
* Performs all necessary setup steps for running requests against the API.
*
* @return the {@link AndroidPublisher} service
*/
private static AndroidPublisher init(){
try {
// Authorization.
Credential credential =
GoogleCredential.fromStream(
AndroidPublisherHelper.class.getResourceAsStream(RESOURCES_CLIENT_SECRETS_JSON))
.createScoped(Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER));
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
// Set up and return API client.
return new AndroidPublisher.Builder(httpTransport, JSON_FACTORY, credential)
.setApplicationName(ApplicationConfig.APPLICATION_NAME)
.build();
} catch (GeneralSecurityException | IOException ex) {
throw new RuntimeException("fail to initialize the publisher APIs client library", ex);
}
}
}
次に、API 呼び出しを行うロジックを追加し、購入を検証して適切なユーザーに利用資格を付与するように、前に作成したレシーバーを変更します。
AndroidPublisherHelper
に、Google Play Developer API の Purchases.products:get エンドポイントから ProductPurchase を取得する次のメソッドを追加します。
/* Fetch the ProductPurchase for the one-time product purchase from
* Purchases.products.get endpoint in the Google Play Developer API
*/
public static ProductPurchase executeProductPurchasesGet(
String packageName, String sku, String purchaseToken) {
try {
ProductPurchase productPurchase =
ANDROID_PUBLISHER.purchases().products().get(packageName, sku, purchaseToken).execute();
return productPurchase;
} catch (IOException ex) {
log.error("Exception was thrown while getting a product purchase", ex);
// It is recommended to apply some retry mechanism, such as exponential backoff, to fetch the purchase in case of transient failures.
return null;
}
}
NotificationMessageReceiver
で購入を検証し、通知に含まれるデータに基づいて、システム内の正しいユーザーに利用資格を付与します。重複処理を回避するため、サーバーで purchaseToken
を常に追跡する必要があります。
@Override
public void receiveMessage(PubsubMessage message, AckReplyConsumer consumer) {
// Decode the data into a String from the message data field.
String jsonString = new String(Base64.getDecoder().decode(message.getData().toStringUtf8()));
// Parse the String into a JSON object.
JSONObject messageJson = new JSONObject(jsonString);
// Fetch the value for certain fields.
String version = messageJson.getString("version");
String packageName = messageJson.getString("packageName");
// Process notification data based on your business requirements.
// Process oneTimeProductNotification in the message.
JSONObject oneTimeProductNotificationJson =
messageJson.getJSONObject("oneTimeProductNotification");
if (oneTimeProductNotificationJson != null) {
String purchaseToken = oneTimeProductNotificationJson.getString("purchaseToken");
String sku = oneTimeProductNotificationJson.getString("sku");
int notificationType = oneTimeProductNotificationJson.getInt("notificationType");
if (notificationType == 1) {
// ONE_TIME_PRODUCT_PURCHASED - A one-time product was successfully purchased by a user.
// Verify that the purchaseToken value does not match any previous purchaseToken values in
// your backend system to avoid duplicate processing.
......
// Fetch the ProductPurchase from Purchases.products.get endpoint
ProductPurchase productPurchase =
AndroidPublisherHelper.executeProductPurchasesGet(packageName, sku, purchaseToken);
if (productPurchase != null && productPurchase.getPurchaseState() == 0) {
// The purchase is valid and in PURCHASED state.
// The account Id set in the App when launching the billing flow.
String obfuscatedExternalAccountId = productPurchase.getObfuscatedExternalAccountId();
// Grant the entitlement to the correct account for obfuscatedExternalAccountId in your
// system.
......
}
}
// Process subscriptionNotification in the message.
JSONObject subscriptionNotificationJson = messageJson.getJSONObject("subscriptionNotification");
if (subscriptionNotificationJson != null) {
......
}
// Process other notification data in the message as needed.
......
}
// Acknowledge the message to avoid repeated delivery.
consumer.ack();
}
7. 購入手続きが完了したことを Google に通知する
利用資格を付与した後、安全なバックエンド サーバーから Play Developer API の purchases.products:consume または purchases.products:acknowledge エンドポイント ポイントを呼び出して、消費型アイテムを使用または非消費型アイテムを承認し、購入が処理されたことを Google に通知する必要があります。
AndroidPublisherHelper
に次のメソッドを追加して、Google Play Developer API で purchases.products:consume または purchases.products:acknowledge を呼び出します。
/* Consume the one-time product purchase by calling
* Purchases.products.consume endpoint in the Google Play Developer API
*/
public static void executeProductPurchasesConsume(
String packageName, String sku, String purchaseToken) {
try {
ANDROID_PUBLISHER
.purchases().products().consume(packageName, sku, purchaseToken).execute();
} catch (IOException ex) {
log.error("Exception was thrown while consuming a product purchase", ex);
// It is recommended to apply some retry mechanism, such as exponential backoff, to ensure the purchase is correctly consumed in case of transient failures.
}
}
/* Acknowledge the one-time product purchase by calling
* Purchases.products.acknowledge endpoint in the Google Play Developer API
*/
public static void executeProductPurchasesAcknowledge(
String packageName, String sku, String purchaseToken) {
try {
ANDROID_PUBLISHER
.purchases().products().acknowledge(packageName, sku, purchaseToken, new ProductPurchasesAcknowledgeRequest()).execute();
} catch (IOException ex) {
log.error("Exception was thrown while acknowledging a product purchase", ex);
// It is recommended to apply some retry mechanism, such as exponential backoff, to ensure the purchase is correctly acknowledged in case of transient failures.
}
}
NotificationMessageReceiver
で、バックエンド サーバーで利用権を付与した後、消費型アイテムの購入を使用します。または、非消費型アイテムの購入を承認します。
@Override
public void receiveMessage(PubsubMessage message, AckReplyConsumer consumer) {
......
String obfuscatedExternalAccountId = productPurchase.getObfuscatedExternalAccountId();
// Grant the entitlement to the correct account for obfuscatedExternalAccountId in your
// system.
......
// If the product is a consumable product, consume the purchase.
AndroidPublisherHelper.executeProductPurchasesConsume(packageName, sku, purchaseToken);
// Or if the product is a non-consumable product, acknowledge the purchase.
// AndroidPublisherHelper.executeProductPurchasesAcknowledge(packageName, sku, purchaseToken);
......
}
承認は、ユーザーに購入の利用権が付与されたことを Google Play に通知するために必須です。利用権を付与したら、すぐに購入を承認する必要があります。
パフォーマンスは良好です。リアルタイム デベロッパー通知を正常に統合し、この Codelab で説明したように、信頼性の高い購入処理を実現しました。次に、すべてが正常に動作していることを確認するために、Google Play 請求サービスの統合をテストするために設計されたユーザー フレンドリーなツールである Play Billing Lab について説明します。
8. Play Billing Lab でテストする
安心してリリースするためには、開発プロセス全体を通して統合をテストする必要があります。Play Billing Lab は、Google Play の課金システムとの統合をテストするのに役立つ無料の Android アプリです。デベロッパーは、Play Billing の機能を簡単にテストし、迅速に統合して、安心してリリースできます。
Play Billing Lab には、次のようなさまざまなテスト機能が用意されており、さまざまなシナリオをテストできます。
- Play Billing Lab で [Play の国] を変更し、設定をテストに適用します。これにより、テスターが実際にテストしている場所に関係なく、さまざまな国や地域でカスタム ユーザー エクスペリエンスをテストできます。
- 同じアカウントで無料試用またはお試し特典を繰り返しテストする
- 他の有効な定期購入者に影響を与えることなく定期購入の価格変更をテストする
- Google Play Billing Library のレスポンス コードをシミュレートして、さまざまなエラー シナリオをテストする
- 定期購入の更新を早めるとテストを高速化
- 実際のお支払い方法でテストする: 特定の購入フロー リスク シグナルを回避する
Google は、Play Billing Lab アプリに新しいテスト機能を継続的に追加しています。Play Billing Lab は Google Play ストアからダウンロードしてインストールできます。また、Play Billing Lab でのテストについて詳しくは、統合をテストするをご覧ください。
Play Billing Lab を使用して BillingResponseCode をテストする
アプリを Play Billing Library と統合する際に、すべての BillingResponseCode フローをテストするのは一般的な課題です。これは、Play ストアと Play のバックエンド間の通信を制御できないためです。Play Billing Lab アプリのレスポンス シミュレーター機能を使用すると、Google Play Billing Library のエラーコード レスポンスを構成して、さまざまな複雑なエラー シナリオをテストできます。
たとえば、アプリで、購入が正常に完了したことを検出した後に購入を消費するロジックを実装したとします。ネットワーク障害によりアプリが購入を消費できなかったシナリオをテストし、バックエンド サーバーの RTDN レシーバがメッセージを取得して購入を正しく処理することを確認します。Response Simulator を使用して、テスト用のシナリオをシミュレートできます。以下では、Play Billing Lab レスポンス シミュレーターを使用してテストする手順について説明します。
レスポンス シミュレータでテストする
レスポンス シミュレータでテストを行うと、アプリは Play Billing Lab と通信して、Play Billing Lab レスポンス シミュレータで設定したレスポンス コードを取得します。
Google Play Billing Library の請求のオーバーライド テストを有効にする
Response Simulator とアプリ間の通信を有効にするには、まずアプリ内から Google Play Billing Library の課金オーバーライド テストを有効にする必要があります。これを行うには、アプリの AndroidManifest.xml
ファイルに次のメタデータタグを追加します。
<manifest ... >
<application ... >
...
<meta-data
android:name="com.google.android.play.largest_release_audience.NONPRODUCTION"
android:value="" />
<meta-data
android:name="com.google.android.play.billingclient.enableBillingOverridesTesting"
android:value="true" />
</application>
</manifest>
更新された AndroidManifest.xml
ファイルを使用してアプリをビルドします。これで、アプリを Play Billing Lab レスポンス シミュレータでテストする準備が整いました。
テスト後にアプリを本番環境にデプロイする場合は、これらのメタデータタグを含まない別の AndroidManifest.xml
ファイルを使用するか、AndroidManifest.xml
ファイルからこれらのタグを削除する必要があります。
Play Billing Library のエラーをシミュレートする
Play Billing Library のエラーをシミュレートしてテストするには、まず Play Billing Lab アプリでレスポンス コードを構成してから、アプリでテストを実行します。
レスポンス コードを設定する
- アプリのライセンス テスター アカウントで Play Billing Lab アプリにログインします。次の図は、[レスポンス シミュレータ] カードを含む Play Billing Lab のダッシュボードを示しています。
- レスポンス シミュレータ カードの [管理] をクリックして、レスポンス シミュレータ画面に移動します。
- プロンプトが表示されたら、アプリの接続ステータスを確認できるよう、Play Billing Lab からの通知を許可してください。
- [Play Billing Library のレスポンスをシミュレートする] スイッチがまだ有効になっていない場合は、有効にします。
- テストする Google Play Billing Library API のレスポンス コードを選択します。消費型の購入のエラーをシミュレートするには、
consumeAsync
API のエラーコードを選択します。選択内容は自動的に保存されます。これで、レスポンス シミュレータは、選択したレスポンス コードをアプリに送信できるようになりました。
アプリをテストする
これで、アプリをテストして、構成したエラー シナリオですべてが想定どおりに動作するかどうかを確認できます。アプリを開き、Play Billing Library API メソッドをトリガーします。アプリが consumeAsync
を呼び出して購入を消費すると、アプリは先ほど設定したエラーコードを受け取ります。エラーコードから、アプリが正しく動作し、バックエンド サーバーが購入を正しく処理しているかどうかを確認できます。
テストが完了したら、[Play Billing Library のレスポンスをシミュレートする] スイッチをオフにして、レスポンスをシミュレートしないようにします。
Play Billing Lab でのテストについて詳しくは、ヘルプセンター記事「ライセンス テスターを使用したアプリ内課金のテスト」をご覧ください。
9. お疲れさまでした
この Codelab を完了すると、アプリの収益化を戦略的に最適化してユーザー エクスペリエンスを向上させ、ユーザー満足度、購入コンバージョン、定期購入の解約率を高めることができます。
リアルタイム デベロッパー通知と Play Billing Lab コンパニオン アプリを活用することで、1 回限りの購入と定期購入の両方の購入ライフサイクル イベントに事前に対応できます。
これらのツールを使用すると、魅力的なユーザーの再獲得戦略を効果的に実装し、統合に関する課題を迅速に解決し、最終的にユーザー エクスペリエンスと収益源を強化して、アプリやゲームを自信を持ってリリースできます。
この Codelab を完了すると、購入フローの全体を管理し、Play Billing Lab で実装を厳密にテストして、シームレスなユーザー エクスペリエンスを実現し、Google Play での収益化の可能性を最大限に引き出すスキルを習得できます。