ドキュメント
Part 4. 発展編
モバイルアプリのアプリ内課金 実装・運用設計ドキュメント の「Part 4. 発展編」をまとめたページです。
Part 4. 発展編
30. 価格変更・プラン変更の詳細
30-1. 基本原則
価格変更は、予定と実際の課金反映を分けて扱います。
価格変更の通知や pending 状態を見ただけで Entitlement を変えてはいけません。
30-1-1. 月額表示価格はどこから取得するか
月額を取得したい という要件は、価格マスタをバックエンドに手入力することではなく、購入画面でストアが返す価格情報を使うこととして設計するのが安全です。
- Apple:
Product.displayPriceを使う - Google:
queryProductDetailsAsync()で取得したProductDetailsからPricingPhase.getFormattedPrice()とgetBillingPeriod()を使う
月額プランなら、その価格をそのまま月額として表示できます。
年額や複数月プランの 月あたり は、billingPeriod と金額から UI 側で換算する参考表示です。実際にいくら・どの周期で請求されるのかを、換算表示より分かる形で併記してください。
30-2. 価格変更専用テーブルを持つべきケース
次の要件があるなら、SubscriptionPriceChange のような専用テーブルを持つ価値があります。
- 同意待ちを追跡したい
- 値上げ失効を通常失効と分けたい
- 管理画面で pending / accepted / applied を見たい
- 通知や CS 案内と連携したい
30-3. プラン変更
Google の upgrade / downgrade、Apple の product change は、現在の契約がどう切り替わるかを監査できるよう、BillingTransaction にイベントとして残すと追跡しやすくなります。
31. prepaid / out-of-app re-subscription 詳細
Google では将来的に高確率で遭遇するため、概念だけは押さえておくと安全です。
31-1. prepaid
- 初回購入だけでなく top-up ごとに acknowledgement が必要
- 自動更新ではなく、都度 purchase が増える
linkedPurchaseTokenや line item の扱いが auto-renewing と異なる
31-2. out-of-app re-subscription
- 期限切れ後に Google Play subscriptions center から再購読すると、
outOfAppPurchaseContextが手掛かりになる expiredExternalAccountIdentifiersは常時使える識別子ではない- acknowledgement 後に参照できなくなる情報があるため、必要なら早めに取り込む
32. 財務・照合観点
32-1. 本ドキュメントの位置づけ
本ドキュメントは、まず権利管理を正しく行うことを主眼にしています。
売上認識や会計照合は別の論点ですが、本番運用では無視できません。
32-2. 最低限押さえたいこと
- 返金・取消・チャージバックを履歴として追えること
- 更新成功回数や継続価格を監査できること
- ストア上の transaction と内部履歴を突合できること
32-3. Google で追加すると強い照合ソース
Google は purchases.subscriptionsv2.get だけでなく、purchases.voidedpurchases.list によって voided order を一覧取得できます。権利管理の主経路は subscription 再照会で足りますが、財務照合や不正利用対策まで見るなら、voided purchase 系を別ラインで取り込むとより堅くなります。
33. 将来拡張
33-1. Web 決済追加に備える設計
将来 Web 決済や別 provider を追加する可能性があるなら、次を守ると拡張しやすくなります。
providerを enum で持つPlanとストア商品マッピングを分離するEntitlementを provider 非依存で定義するBillingTransactionをイベントログとして設計する
33-2. それでも初回リリースではやりすぎない
拡張を見据えることと、初回から抽象化しすぎることは別です。
初回は Apple / Google の 2 provider を素直に実装し、そのうえで provider 境界だけは明確にしておく、という方針が最も現実的です。