Google
PR

【Google】リアルタイムデベロッパー通知(RTDN)の仕組みと設定

saratogax
記事内に商品プロモーションを含む場合があります

Google Play のアプリ内課金では、購入や定期購入の状態が変わったことを、サーバーへリアルタイムに知らせる仕組みが用意されています。

それが、リアルタイムデベロッパー通知(Real-time developer notifications: RTDN)です。

このページでは、RTDN を受け取る仕組みと設定手順、通知データの構造、受信後のハンドリングの基本をまとめていきます。

アプリ内課金全体の中での位置づけは、以下のまとめページもあわせてご覧ください。

あわせて読みたい
【Google】アプリ内課金(Google Play Billing)の全体像と記事まとめ
【Google】アプリ内課金(Google Play Billing)の全体像と記事まとめ

リアルタイムデベロッパー通知(RTDN)とは

RTDN は、定期購入の更新やキャンセル、商品の購入や払い戻しなど、課金に関するイベントが発生したときに、開発者のサーバーへ通知を届ける仕組みです。

通知には、イベントの種類や購入トークンなどの情報が含まれています。

ただし、RTDN が伝えるのは「状態が変わった」という事実だけで、購入の詳細までは含まれません。

そのため通知を受け取ったら、Google Play Developer API で最新の状態を取得し直すのが基本的な流れになります。

通知を起点にすることで、有効期限が近い購入だけをバッチで定期チェックするような無駄な処理を省けます。特にサブスクリプションの運用では欠かせない仕組みと言えます。

RTDN を受け取る仕組み(Cloud Pub/Sub)

RTDN は、開発者のサーバーへ直接 HTTP で届くわけではありません。

実は、Google Cloud の Cloud Pub/Sub というメッセージングサービスを経由して配信されます。

そのため、AWS やオンプレミスでバックエンドを運用している場合でも、RTDN を使うには Google Cloud のプロジェクトと Cloud Pub/Sub の設定が必要です。

設定の大きな流れは、次の 4 ステップです。

  1. Cloud Pub/Sub でトピックを作成する
  2. トピックにサブスクリプションを作成する
  3. トピックに Google Play の公開権限を付与する
  4. Google Play Console で RTDN を有効化する

1. トピックを作成する

Cloud Pub/Sub の「トピック」は、通知メッセージの送り先となる入れ物です。

Google Cloud Console で対象プロジェクトを選び、Pub/Sub からトピックを 1 つ作成します。

トピック名は、最終的に projects/{プロジェクトID}/topics/{トピックID} という形式のフルパスで扱います。

2. サブスクリプションを作成する

作成したトピックには、メッセージの受け取り方を決める「サブスクリプション」を紐づけます。

サブスクリプションには、プッシュ型とプル型の 2 種類があります。

配信タイプ通知の届き方
プッシュ型Pub/Sub が、指定した HTTPS エンドポイントへ通知を送信する
プル型バックエンド側から Pub/Sub に通知を取りに行く
※表は横スクロールできます

公式ドキュメントでは、どちらにすべきか迷う場合は、実装しやすいプッシュ型が推奨されています。

プル型は大量メッセージのリソース最適化に向いた方式で、RTDN の用途ではあまり当てはまらない、という説明です。

3. トピックに公開権限を付与する

Google Play から Pub/Sub のトピックへ通知を書き込めるよう、トピックに公開権限を付与します。

具体的には、トピックの権限設定で、次のサービスアカウントに「Pub/Sub パブリッシャー」ロールを付与します。

google-play-developer-notifications@system.gserviceaccount.com

この権限がないと、Google Play 側からトピックへ通知を発行できません。

4. Google Play Console で RTDN を有効化する

最後に、Google Play Console 側で通知の送信先を設定します。

対象アプリの「収益化」→「収益化のセットアップ」を開き、「リアルタイムデベロッパー通知」のセクションへ進みます。

「リアルタイム通知を有効にする」にチェックを入れ、トピック名の欄に projects/{プロジェクトID}/topics/{トピックID} 形式のフルパスを入力します。

「テストメッセージを送信」を押すと、設定が正しいかどうかをその場で確認できます。

このセクションでは、受け取る通知の種類も選べます。サブスクリプションだけでなく 1 回限りの購入も扱う場合は、使い切り商品の通知が有効になっているか確認しておきましょう。

通知データの構造

RTDN の通知は、Cloud Pub/Sub のメッセージとして届きます。

メッセージの本文(data)は base64 でエンコードされており、デコードすると DeveloperNotification という JSON オブジェクトが得られます。

DeveloperNotification には、以下のフィールドが含まれます。

項目内容
version通知のバージョン
packageNameアプリのパッケージ名
eventTimeMillisイベント発生日時(ミリ秒)
subscriptionNotification定期購入に関する通知の場合に含まれるオブジェクト
oneTimeProductNotification1 回限りの購入に関する通知の場合に含まれるオブジェクト
voidedPurchaseNotification無効化された購入に関する通知の場合に含まれるオブジェクト
testNotificationテスト通知の場合に含まれるオブジェクト
※表は横スクロールできます

このうち subscriptionNotificationoneTimeProductNotificationvoidedPurchaseNotificationtestNotification は相互排他で、1 つの通知にはいずれか 1 つだけが含まれます。

つまり、どのオブジェクトが入っているかを見れば、通知の大きな種類を判別できます。

通知の種類

ここからは、通知に含まれる 4 種類のオブジェクトと、それぞれの通知タイプを紹介します。

定期購入の通知(SubscriptionNotification)

定期購入に関する通知で、versionnotificationTypepurchaseToken のフィールドを含みます。

notificationType には、状態変化の種類を表す整数値が入ります。

定数名内容
1SUBSCRIPTION_RECOVEREDアカウント保留状態から定期購入が回復した
2SUBSCRIPTION_RENEWED有効な定期購入が更新された
3SUBSCRIPTION_CANCELED定期購入がキャンセルされた(ユーザー操作または決済不備による)
4SUBSCRIPTION_PURCHASED新しい定期購入が購入された
5SUBSCRIPTION_ON_HOLD定期購入がアカウント保留状態に入った
6SUBSCRIPTION_IN_GRACE_PERIOD定期購入が猶予期間に入った
7SUBSCRIPTION_RESTARTEDユーザーが Google Play から定期購入を再開した
8SUBSCRIPTION_PRICE_CHANGE_CONFIRMED価格変更がユーザーに確認された(非推奨)
9SUBSCRIPTION_DEFERRED定期購入の更新日時が延長された
10SUBSCRIPTION_PAUSED定期購入が一時停止された
11SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED定期購入の一時停止スケジュールが変更された
12SUBSCRIPTION_REVOKED有効期限前に定期購入が取り消された
13SUBSCRIPTION_EXPIRED定期購入の有効期限が切れた
17SUBSCRIPTION_ITEMS_CHANGED定期購入バンドル内のアイテムが変更された
18SUBSCRIPTION_CANCELLATION_SCHEDULED分割払いの定期購入のキャンセルが、コミットメント期間の終了時に有効になるよう予約された
19SUBSCRIPTION_PRICE_CHANGE_UPDATED定期購入アイテムの価格変更の詳細が更新された
20SUBSCRIPTION_PENDING_PURCHASE_CANCELED定期購入の保留中トランザクションがキャンセルされた
22SUBSCRIPTION_PRICE_STEP_UP_CONSENT_UPDATED段階的な価格引き上げ(price step-up)の同意期間が始まった、またはユーザーが同意した(price step-up が必須の地域のみ)
※表は横スクロールできます

かつて SubscriptionNotification には商品IDを表す subscriptionId が含まれていましたが、現在のリファレンスでは記載されていません。商品の特定は、通知後に取得する購入リソースの lineItems 側で行うのが正式な方法です。

各状態が定期購入のライフサイクルの中でどう遷移するかは、定期購入のページで詳しく解説しています。

あわせて読みたい
【Google】アプリ内課金のサブスクリプションのライフサイクル
【Google】アプリ内課金のサブスクリプションのライフサイクル

1回限りの購入の通知(OneTimeProductNotification)

1 回限りの購入(使い切り商品・非消費型商品)に関する通知です。

versionnotificationTypepurchaseTokensku(商品ID)のフィールドを含みます。

定数名内容
1ONE_TIME_PRODUCT_PURCHASED1 回限りの商品が購入された
2ONE_TIME_PRODUCT_CANCELED保留中だった 1 回限りの商品の購入がキャンセルされた
※表は横スクロールできます

1 回限りの購入のハンドリングは、以下のページで解説しています。

あわせて読みたい
【Google】アプリ内課金の1回限りの購入ライフサイクル
【Google】アプリ内課金の1回限りの購入ライフサイクル

無効購入の通知(VoidedPurchaseNotification)

払い戻しやチャージバックなどで無効になった購入に関する通知です。

purchaseTokenorderIdproductTyperefundType のフィールドを含みます。

フィールド内容
productType1PRODUCT_TYPE_SUBSCRIPTION(定期購入)
productType2PRODUCT_TYPE_ONE_TIME(1 回限りの購入)
refundType1REFUND_TYPE_FULL_REFUND(全額返金)
refundType2REFUND_TYPE_QUANTITY_BASED_PARTIAL_REFUND(数量に応じた一部返金)
※表は横スクロールできます

無効購入の取得と扱いについては、以下のページで解説しています。

テスト通知(TestNotification)

動作確認用の通知で、version フィールドのみを含みます。

前述の Google Play Console の「テストメッセージを送信」を押すと、この testNotification が届きます。

通知を受け取った後の処理

RTDN を受け取ったら、基本となる処理の流れは次のとおりです。

  1. Pub/Sub メッセージの data を base64 デコードし、DeveloperNotification を取り出す
  2. 含まれているオブジェクトの種類と notificationType を確認する
  3. purchaseToken を使い、Google Play Developer API で最新の購入状態を取得する
  4. 取得した状態をもとに、バックエンドの購入情報やアクセス権を更新する

ポイントは、通知タイプを鵜呑みにせず、必ず Developer API で最新状態を取得し直すことです。

定期購入なら purchases.subscriptionsv2.get、1 回限りの購入なら purchases.products.get で状態を確認します。

また、Pub/Sub のメッセージは、配信順序が保証されず、同じ通知が重複して届くこともあります。

そのため、通知を受け取った後の処理は冪等(何度実行しても結果が変わらない)になるよう設計しておくと安心です。

受け取った通知の内容は、ログやデータベースに履歴として残しておくと、トラブル時の調査にも役立ちます。

新規購入(SUBSCRIPTION_PURCHASED / ONE_TIME_PRODUCT_PURCHASED)については、サイト側のユーザーと購入を紐づける必要があるため、RTDN ではなくアプリ経由でバックエンドへレシートを送る方が扱いやすいケースもあります。

まとめ

Google Play のリアルタイムデベロッパー通知(RTDN)について、仕組みと設定をまとめてきました。

RTDN は Cloud Pub/Sub を経由するため設定の手間はありますが、状態変化を起点にできるので、特にサブスクリプションの運用では欠かせません。

通知はあくまで「変化のきっかけ」として扱い、最終的な判断は Developer API で取得した最新状態に委ねる、という設計を意識しておきましょう。

参考(出典)

ABOUT ME
saratoga
saratoga
フリーランスエンジニア
仕事にも趣味にも IT を駆使するフリーランスエンジニア。技術的な TIPS や日々の生活の中で深堀りしてみたくなったことを備忘録として残していきます。
記事URLをコピーしました