【Google】定期購入のレシート検証をPHPとKotlinで実現する
前回、GooglePlayBilling(Android)の都度課金についてまとめてみましたが、最近は月額課金のサービスが多くなり、都度課金以上に需要が増えてきています。
定期購入のすべてが月額というわけではない(2週間や年単位のものもある)ですが、一般的にサブスクリプションと呼ばれるものですね。
シンプルに 1 種類だけの月額プランを提供しているサービスもあれば、値段別に複数のプランを用意している複雑なサービスもあります。
前者であれば実装や運用も少しは楽になりそうですが、後者の場合はプランのアップグレードやダウングレードなど考慮する点が増え煩雑になります。
今後の定期購入の実装に向けて、今回は事前調査した内容をまとめておきたいと思います。
設計や実装を進める中で、新しい内容で置き換えていきたいと思います
別途、Google の購入レシートをまとめてみましたので、興味のある方は以下もご覧ください。
Androidアプリのガイド
今回はネイティブの実装には大きく触れませんが、まずは Android のネイティブアプリの実装向けのガイドラインや仕様です。
定期購入の場合、都度課金と同じく、初回購入時に購入トークン(purchaseToken)とオーダーID(orderId)が発行されます。
都度課金の場合は、毎回「購入トークン」と「オーダーID」が新しく発行されますが、定期購入の場合、購読を継続している間は「購入トークン」は変わらず、「オーダーID」も連番が付与されるくらいの違いしかありません。
簡単なイメージですが、1 月に購読を開始して 4 月に解約、再度 10 月に再購読した場合のシミュレーションです。
年月 | 購入トークン | 注文ID |
---|---|---|
2023年1月 | TOKEN-A | ORDER-A |
2023年2月 | TOKEN-A | ORDER-A.0 |
2023年3月 | TOKEN-A | ORDER-A.1 |
2023年4月 | TOKEN-A | ORDER-A.2 |
2023年10月 | TOKEN-B | ORDER-B |
再購入した場合や、プランを変更(アップグレード、ダウングレード)した場合のみ、新しい「購入トークン」と「オーダーID」が生成されます。
定期購入アイテムの設定
定期購入アイテムは都度課金のアイテムと違って、設定する項目が多く存在します。
いくつか、よく使われそうなものを紹介します。
請求対象期間
まずは、請求対象期間ですが、通常の月額課金であれば「1ヶ月」となります。他にも「週単位」「3ヶ月」「6ヶ月」「年単位」が選択可能です。
この設定した期間に応じて、Google が期限になると自動的に課金をしてくれます。
無料試用期間(Free Trial)
無料試用期間は、一般的に「初月無料」や「最初の2週間無料」みたいなお試し期間になります。
ユーザが利用してみて、良いと思えば継続してもらうという体験期間のようなものですね。
Android の場合、無料試用期間は 3 日以上から設定可能です。
猶予期間(Grace Period)
猶予期間は、ユーザのクレジットカードの有効期限切れなどで、課金対象日に決済がうまくいかなかった時に設けられる期間です。
Google はすぐに解約扱いにせず、月額の場合はデフォルトで 7 日間、ユーザが決済不備の状態を直すまで猶予を与えてくれます。
この期間内にユーザが決済手段を正常に戻せば継続になりますし、ユーザが放置すれば、猶予期間終了後に解約となります。
ユーザには定期的に、決済不備がある旨、Google からメールなどで通知が届きますので、この期間に復活するユーザは多くなりそうなイメージがあります。
アカウントの一時停止(Account Hold)
アカウントの一時停止は、Android アプリ(Google Play Console)側の設定に依存しますが、設定が有効になっていると、猶予期間を超えてしまった場合に即解約とはならず、一時停止状態になります。
この間、Google は決済不備を修正するのを待ってくれて、期間内に改善されれば購読が継続扱いになります。
こちらは 30 日間と期間が決まっており、これ以上は待ってもらえません。これを過ぎれば解約となります。
一時停止については、別途ユーザトリガーの一時停止もありますので、詳しくは以下にまとめています。
プランのアップグレードとダウングレード
冒頭でも触れたように、複数のプランを用意する場合はアップグレードやダウングレードを考慮しておかなければいけません。
Google 側で、現在の定期購入の未使用分を新しい定期購入に柔軟に移行してくれるようですが、お問い合わせや FAQ など、ユーザへの説明の必要性も出てくるので運用する側もしっかりと理解しておく必要があります。
少しややこしいですが、例えば月額 500 円のコンテンツを購読していて、半月後に月額 1000 円のプランに変更したとします。
この時、現在の月額コンテンツは停止となり、残り半月分(250円相当)が新しいプランへ適用となります。
ただし 250 円相当なので、新しいプランが利用できるのは月額 1000 円の 4 分の 1 にあたる 7 日程度です。
この期間が過ぎると新しいプランの課金が継続となり、月額 1000 円でコンテンツが楽しめるようになります。
ユーザにとってもコンテンツ提供側にとっても損になっていないので、ここは GooglePlay のいいところですね。
月額課金のレシート検証
都度課金の時と同じく、月額のコンテンツを購入すると GooglePlay からレシートデータ発行されます。
これをネイティブアプリから受け取り、サーバサイド側で Google のレシート検証 API で整合性チェックと詳細な情報の取得を行います。
現在は v2 がメインですが、2023 年 12 月現在、まだ v1 と完全互換性がなく v1 も非推奨(deprecated)になっているわけではありません。
都度課金と被りますが、確認するのは大きく 4 つ。
・対象プロダクトコードの一致
・電子署名のチェック
・レシート検証 API でレスポンスが返る
・購読状態が継続で有効期限内である
API のレスポンスとして返ってきた内容のうち、主に以下の項目が重要になってきます。
{
“kind”: “androidpublisher#subscriptionPurchase”,
“startTimeMillis”: long,
“expiryTimeMillis”: long,
“autoRenewing”: boolean,
“paymentState”: integer,
“cancelReason”: integer,
“userCancellationTimeMillis”: long,
“orderId”: string,
“linkedPurchaseToken”: string,
“purchaseType”: integer,
}
購読期間が startTimeMillis と expiryTimeMillis、自動購読のステータスが autoRenewing になります。
月額の更新処理の際には、この辺りの情報が参考になってきそうです。
paymentState については、0 の「支払い保留」になった時は決済に失敗している可能性が高いので、猶予期間を過ぎても決済が完了しない場合は購読停止とします。
1 の「支払済」や 2 の「無料トライアル」についてはスルーして大丈夫そうです。
以前はなかったようですが、3 で「保留中のアップグレード/ダウングレード」が追加されているので、これは別途考える必要がありそうですね。
また、都度課金と同じくテストユーザによる購入の場合は purchaseType が 0 になります。
購読の有効期限更新について
最初は、有効期限の 24 時間くらい前から定期的にバッチで更新確認を行うことを考えていましたが、以下のページでまとめた通り、リアルタイムデベロッパー通知を活用することにしました。