Google Billing Libraryの定期購入後の「購入をフェッチする」の挙動について
はじめに
Google Billing Library ではアプリ内で全ての購入を確実に処理するために行なった購入を取得するためのメソッドとして queryPurchasesAsync
が用意されている。また購入履歴の取得メソッドとして queryPurchaseHistory
も用意されている。これらメソッドの挙動が各状態でどのように変化するのかをまとめた。
購入をフェッチする
公式ドキュメントの購入をフェッチするにもあるように購入時に返ってきた結果だけを扱うとネットワークにつながっていないケースや別のデバイスに切り替えたときやアプリ側で購入が行われた場合などに対応できない。そのために購入があったことを確認するために queryPurchasesAsync
や qureyPurchaseHistory
(Google Billing Library 7.0.0 から非推奨)などを使って購入情報・履歴を取得する必要がある。それぞれのメソッドのリファレンスの説明は以下の通り。
queryPurchasesAsync
queryPurchasesAsync() は、有効な定期購入と未消費の 1 回だけの購入のみを返すことに注意してください。
queryPurchaseHistoryAsync (Google Billing Library 7.0.0 から非推奨)
queryPurchaseHistoryAsync() は、各アイテムに関してユーザーが行った直近の購入の情報を返します。期限切れの購入やキャンセル済みの購入、消費済みの購入も対象に含まれます。
挙動の検証
検証に使用した Google Billing Library のバージョンは 6.0.1。使用したアプリは自作した google-billingを使用。検証内容は以下の通り。(Google Billing Library 7.0.0 から queryPurchaseHistoryAsync
は非推奨。購入履歴などはバックエンドで管理することを推奨している。)
queryPurchasesAsync
およびqueryPurchaseHistoryAsync
から値が返却されるか?
各状態で公式ドキュメントの以下の内容を検証するために各状態で購入や購入履歴(PurchaseやPurchaseHistoryRecordクラス)が各メソッドで取得できるかの検証を行う。
queryPurchasesAsync() メソッドでは、引き続き猶予期間中の購入を返します。ユーザーに定期購入の利用資格があるかどうかをアプリが queryPurchasesAsync のみに基づいて確認している場合、このような定期購入は Play Billing Library で有効とされるため、アプリは自動的に猶予期間を処理します。
引用元:猶予期間
アカウントの一時停止中の定期購入は queryPurchasesAsync() メソッドから返されないため、アプリでこのメソッドを使用して既存の購入を表示している場合は、デフォルトでアカウントの一時停止をサポートする必要があります。
引用元:アカウントの一時停止
ユーザーが定期購入を一時停止できるようにすることで、自主的な解約を削減できます。一時停止機能を有効にすると、契約期間の間隔に応じて、ユーザーは 1 週間から 3 か月の間、定期購入を一時停止できます。
引用元:定期購入の一時停止
各状態の再現手順
一部、状態を再現するために必要な手順や時系列を以下に示す。
1. 猶予期間(GracePeriod) ~ アカウント一時停止(Account Hold) ~ 自動キャンセルまでの手順
アプリでの猶予期間やアカウント一時停止の再現は定期購入固有の機能をテストするを参考。以下は実施した時系列とイベント、状態。
時間 | イベント | 状態 |
---|---|---|
13:28 | 1ヶ月の定期購入を購入 | |
13:28 | Google Playアプリの定期購入から支払い方法を非承認へ変更 | |
13:33 | Payment declined のメール届く | 1ヶ月の定期購入の支払いが不承認になり猶予期間開始 |
13:38 | subscription suspend due to payment issue のメールが届く | 猶予期間停止、アカウント一時停止期間開始 |
13:48 | subscription has been canceled のメールが届く | アカウント一時停止期間停止、キャンセルされる |
2. 手動キャンセルの手順
手動キャンセルした時の時系列とイベントや状態。
時間 | イベント | 状態 |
---|---|---|
1:51 | 1ヶ月の定期購入を購入 | |
1:51 | Google Playアプリの定期購入から購入したものをキャンセル | |
1:55 | キャンセル期限を迎える | 定期購入の期限切れ |
3. 定期購入の一時停止(Pause)までの手順
アプリ内で任意の定期購入を購入し、Google Playのアプリから購入した定期購入を一時停止することで再現できる。
時間 | イベント | 状態 |
---|---|---|
14:18 | 1ヶ月の定期購入を購入 | |
14:20 | Google Playアプリの定期購入から購入したものを一時停止 一時停止予定のメールが届く |
|
14:23 | 一時停止開始のメールが届く | 一時停止期間開始 |
14:28 | 自動更新のメールが届く | 一時停止期間終了 |
結果
再現手順1の結果は以下の通り。
*自動キャンセルはアカウント一時停止期間が終わった後のキャンセルを指す。
猶予期間 (Grace Period) |
アカウント一時停止 (Account Hold) |
自動キャンセル時(≒期限切れ)* | |
---|---|---|---|
queryPurchasesAsync (13:28に購入実施) |
購入が返却される isAutoRenewing=true |
購入が返却されない isAutoRenewing=n/a |
購入が返却されない isAutoRenewing=n/a |
queryPurchaseHistoryAsync (13:28に購入実施) |
購入履歴が返却される |
購入履歴が返却される |
購入履歴が返却されない |
再現手順2の結果は以下の通り。
*手動キャンセルはGoogle Playアプリの定期購入からユーザ自らキャンセルした瞬間のものを指す
*期限切れはGoogle Playアプリの定期購入からユーザ自らキャンセルし、期限を迎えたものを指す
手動キャンセル時* | 期限切れ* | |
---|---|---|
queryPurchasesAsync (13:51に購入実施) |
購入が返却される isAutoRenewing=false |
購入が返却されない isAutoRenewing=n/a |
queryPurchaseHistoryAsync (13:51に購入実施) |
購入履歴が返却される |
購入履歴が返却される |
アプリの再インストール、デバイスの切り替え、別Googleアカウントへの切り替え時の結果は以下の通り。
再インストール (21:01に購入実施したものに対しての結果) |
デバイス切り替え(同じGoogleアカウント) (21:10に購入実施したものに対して) |
別物のGoogleアカウントへ切り替え (21:16に購入実施したものに対して) |
|
---|---|---|---|
queryPurchasesAsync |
購入が返却される isAutoRenewing=true |
切り替え先のデバイスでも購入が返却される isAutoRenewing=true |
切り替え先のGoogleアカウントにて購入が返却されない isAutoRenewing=n/a |
queryPurchaseHistoryAsync |
購入履歴が返却される |
切り替え先のデバイスでも購入履歴が返却される |
切り替え先のGoogleアカウントにて購入履歴が返却されない |
再現手順3の結果は以下の通り。
定期購入開始時 | 定期購入一時停止時 | 定期購入一時停止解除時(自動更新時) | |
---|---|---|---|
queryPurchasesAsync (14:18に購入実施) |
購入が返却される isAutoRenewing=true |
購入が返却されない |
購入が返却される isAutoRenewing=true |
queryPurchaseHistoryAsync (14:18に購入実施) |
購入履歴が返却される |
購入履歴が返却される |
購入履歴が返却される |
まとめ
各種状態において queryPurchasesAsync
と queryPurchaseHistoryAsync
の挙動をまとめると以下のようになる。⭕️が返却される。❌が返却されないことを表す。
定期購入一時停止中 (Pause) |
猶予期間中 (Grace Period) |
アカウント一時停止中 (Account Hold) |
アカウント一時停止からの自動キャンセル(≒期限切れ) | 手動キャンセル時 | 手動キャンセルからの期限切れ | 再インストール | デバイス切り替え | Googleアカウント切り替え | |
---|---|---|---|---|---|---|---|---|---|
queryPurchasesAsync | ❌ | ⭕️ | ❌ | ❌ | ⭕️ | ❌ | ⭕️ | ⭕️ | ❌ |
queryPurchaseHistoryAsync | ⭕️ | ⭕️ | ⭕️ | ❌ | ⭕️ | ⭕️ | ⭕️ | ⭕️ | ❌ |
余談(queryPurchaseHistoryの挙動)
queryPurchaseHistory
の挙動についてドキュメントでは「直近の購入情報のほかに期限切れやキャンセル済みも返す」とあったので今までの購入が多い場合はかなりの数の購入情報が返却されると思っていた。しかし、挙動を見てみると件数が思ったより少ないため疑問に思った。
改めて挙動を観察すると ProductId を Key にデータを保存したものを返しているような感じだった(以下のイメージ。今まで2商品しか購入したことがなければ2件。2商品とは別の商品を購入しない限りは件数は増えないイメージ)。
つまり、ある定期購入商品が購入されたときに1件追加、キャンセルされた時に新たに1件追加されるといった管理の仕方ではなく、初めて購入する定期購入商品の時に追加され、キャンセルや期限切れ後、再度購入された場合は上書き保存されるといった管理の仕方をしていそうな感じだった。そのため queryPurchaseHistory
が返す件数は今まで購入した定期購入商品数になるのではないかと思う。
*挙動やイメージについてはあくまで想像です。
2024/5月追記
Google Billing Library 7.0.0 でも挙動は同じことを確認しましたが、queryPurchaseHistory
は非推奨とのことなので使用し続けるのは自己責任でお願いします。
Discussion