【Google】アプリ内課金の1回限りの購入ライフサイクル
Google Play のアプリ内課金のうち、「1回限りの購入(都度課金)」は、購入のたびに完結するタイプの商品です。
定期購入に比べるとライフサイクルはシンプルですが、消費(consume)や承認(acknowledge)の扱いには注意が必要です。
このページでは、1回限りの購入のライフサイクルと、バックエンドでの処理方法をまとめていきます。
アプリ内課金全体の中での位置づけは、以下のまとめページもあわせてご覧ください。
1回限りの購入のライフサイクル
1回限りの購入は、定期購入のように更新や猶予期間といった状態を持ちません。
公式ドキュメントでは、購入処理の流れがおおよそ次のように整理されています。
- 購入できる商品をユーザーに提示する
- 購入フローを起動し、ユーザーに購入してもらう
- サーバー(バックエンド)で購入を検証する
- ユーザーにコンテンツを提供する
- コンテンツの提供を承認(acknowledge)する。消費型の商品は、再購入できるように消費(consume)する
シンプルに見えますが、消費型か非消費型か、購入が確定済みか保留中かによって、処理を分ける必要があります。
消費型と非消費型
1回限りの購入の商品は、消費型(consumable)と非消費型(non-consumable)の 2 種類に分かれます。
| 種類 | 特徴 | 購入後の処理 |
|---|---|---|
| 消費型 | 繰り返し購入できる(コイン・ジェム・一時的なアイテムなど) | 消費(consume)する |
| 非消費型 | 1 ユーザーにつき 1 回だけ購入できる(永続機能・プレミアムコンテンツなど) | 承認(acknowledge)する |
消費型は、消費するとそのトークンが再購入できる状態に戻ります。
非消費型は消費せず、承認だけを行います。
購入状態(PurchaseState)の確認
購入を処理する前に、その購入が「支払い済み」なのか「保留中」なのかを確認します。
Google Play Billing Library の購入状態(PurchaseState)には、次の 3 つの値があります。
| 状態 | 内容 |
|---|---|
| PURCHASED | 支払いが完了し、購入を処理できる状態。コンテンツの提供はこの状態のときだけ行う |
| PENDING | 支払い完了までに追加の手順が必要な状態。この状態ではコンテンツを提供しない |
| UNSPECIFIED_STATE | 状態が不明、または未初期化 |
大切なのは、コンテンツの提供や承認は PURCHASED のときだけ行うという点です。
PENDING の購入に対してコンテンツを提供してしまうと、支払いが完了しないまま権利を渡すことになってしまいます。
承認(acknowledge)と消費(consume)
コンテンツを提供したら、購入を処理したことを Google に伝える必要があります。
非消費型の商品は承認(acknowledge)、消費型の商品は消費(consume)を行います。
消費は承認も兼ねるため、消費型の商品で別途 acknowledge を呼ぶ必要はありません。
処理が重複しないよう、承認の前には isAcknowledged() で承認済みかどうかを確認しておくと安心です。
保留中の購入(PENDING)
保留中の購入とは、ユーザーが購入を開始してから、実際に支払いが処理されるまでに追加の手順が必要な購入のことです。
たとえば、コンビニなどの実店舗で後から現金で支払うケースがこれにあたります。
この場合、ユーザーは受け取ったコードを店舗で提示して支払い、支払いが完了すると Google から通知が届きます。
アプリは、保留中の購入をサポートする必要があります。
具体的には、BillingClient の生成時に enablePendingPurchases() を呼び出します。
支払いが完了すると購入状態が PURCHASED に変わり、キャンセルされた場合は後述の ONE_TIME_PRODUCT_CANCELED 通知が届きます。
なお、PENDING の購入では orderId が null になり、PURCHASED に変わったときに値が入ります。
orderId が入っている前提で検証していると、保留中の購入で想定外の挙動になりやすいので注意が必要です。
RTDN での通知
1回限りの購入も、リアルタイムデベロッパー通知(RTDN)で状態変化を受け取れます。
ユーザーが購入またはキャンセルすると、Google Play は OneTimeProductNotification を送信します。
- ONE_TIME_PRODUCT_PURCHASED … 1回限りの商品が購入された
- ONE_TIME_PRODUCT_CANCELED … 保留中だった購入がキャンセルされた
ただし、1回限りの購入の RTDN は、Google Play Console で対象の通知を有効にしていないと送信されません。
RTDN の設定方法や通知データの構造は、以下のページで解説しています。
バックエンドでの処理
セキュリティ上の理由から、購入の検証と処理はバックエンドで行うことが推奨されています。
バックエンドでは、Google Play Developer API の purchases.products.get を使い、購入トークンから最新の状態を取得します。
処理の重複を防ぐため、取得した結果のフィールドを確認しておきましょう。
- 消費型 …
consumptionStateで、すでに消費済みでないかを確認する - 非消費型 …
acknowledgementStateで、すでに承認済みでないかを確認する
消費型の商品をバックエンドで確実に消費したい場合は、purchases.products.consume を使う方法もあります。
また、同じ購入を二重に処理しないよう、購入トークン(purchaseToken)を一意キーとして、既存の購入と重複していないかを確認します。
orderId はプロモーションコードを使った購入などでは生成されないため、重複チェックや主キーには使わないよう公式に推奨されています。
まとめ
Google のアプリ内課金における「1回限りの購入」のライフサイクルを紹介してきました。
定期購入よりは状態がシンプルですが、消費型か非消費型か、PURCHASED か PENDING かによって処理が変わる点は押さえておきたいところです。
とくに、3 日以内の承認・消費を忘れると購入が自動で取り消されてしまうので、バックエンドでの処理フローはしっかり組んでおきましょう。
参考(出典)
- Integrate the Google Play Billing Library into your app(Google)
- purchases.products.get(Google Play Developer API)
