mcpField
R
rc-subscription-states

rc-subscription-states

github.com/revenuecat開発76643 回インストール1 日前に更新
リポジトリ

rc-subscription-states について

Android 開発者向けに、RevenueCat のサブスクリプションアクセス判定と UI への状態反映を説明するスキルです。権利情報、キャッシュまたは最新の CustomerInfo、更新リスナーの使い方を扱います。

主な機能

  1. 01権利の有効状態によるアクセス制御
  2. 02更新、期限、請求状態の確認
  3. 03キャッシュまたは最新の CustomerInfo の利用
  4. 04顧客情報リスナーによる UI 更新
  5. 05識別済みユーザーと匿名ユーザーの処理

活用シーン

  1. 01サブスクリプションに応じたプレミアムコンテンツ表示
  2. 02請求問題や有効期限の通知
  3. 03サーバー側の付与後のアクセス状態更新
  4. 04購入や復元後のアクセス UI 同期

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/revenuecat/ai-toolkit --skill rc-subscription-states

インストール後、Claude Code で/rc-subscription-statesを入力して読み込まれたか確認します。

詳細

サブスクリプションの状態

Android で CustomerInfo と EntitlementInfo を使って、ユーザーがアクセス権を持っているかどうかを判定し、状態に応じた UI を表示します。

フェーズ 1:確認

コードを書く前に、実際に何を確認するのかを把握します。

  • 機能の利用条件となるエンタイトルメント ID は何ですか?(例:pro_access)
  • アクセスの有無を示す単純なブール値だけが必要ですか?それとも、アクセス権の有無の理由(請求の問題、キャンセル済みだが支払い期間中、一時停止中)も説明する必要がありますか?
  • キャッシュされた値(高速ですが、古い可能性があります)と、最新の値(サーバーが正とする値)のどちらが必要ですか?
  • 起動時に UI を一度だけ更新しますか?それとも、購入、復元、バックグラウンド更新などのリアルタイムな変更に反応させますか?

アクセスの有無だけが必要なら、必要なのは isActive だけです。それ以外はすべて任意の補足情報です。

フェーズ 2:計画

Google の 7 つの状態と RevenueCat のブール値

Google Play Developer API を使って独自のトラッカーを実装すると、7 つのサブスクリプション状態を対応付け、どの状態でアクセス権を付与するかを決める必要があります。

Google の状態アクセス権を付与するか
ACTIVEはい
IN_GRACE_PERIODはい
CANCELED(expirationDate より前)はい
ON_HOLDいいえ
PAUSEDいいえ
EXPIREDいいえ
PENDINGいいえ

RevenueCat はバックエンドで Google の SubscriptionPurchaseV2 リソースからこの状態を計算し、1 つのフィールド EntitlementInfo.isActive として公開します。状態機械を実装する代わりに、ブール値を読み取れます。

何をいつ読み取るか
必要な情報フィールド
ユーザーは現在アクセス権を持っていますか?entitlement.isActive
サブスクリプションは期間終了時に更新されますか?entitlement.willRenew
有料アクセスはいつ終了しますか?entitlement.expirationDate
トライアル、導入価格、前払い、通常期間のどれですか?entitlement.periodType
支払いに問題がありますか?entitlement.billingIssueDetectedAt
ユーザーはキャンセル済みですが、まだ期間が残っていますか?entitlement.unsubscribeDetectedAt
エンタイトルメントを発行したストアはどれですか?entitlement.store
判断ルール
  • 機能の利用可否は isActive == true で判定します。それ以外は使いません。
  • 支払い方法の修正を促すには、billingIssueDetectedAt != null を使います。
  • アクセス権がまだ有効な間に更新を促すには、unsubscribeDetectedAt != null と expirationDate を使います。
  • 請求の問題も明示的なキャンセル日時もない場合、更新されないことを通知するには !willRenew を使います。

フェーズ 3:実装

CustomerInfo を読み取り、アクセス権を確認する
val customerInfo = Purchases.sharedInstance.awaitCustomerInfo()
val hasAccess = customerInfo.entitlements["pro_access"]?.isActive == true

awaitCustomerInfo() はディスクキャッシュをすぐに返し、その後バックグラウンドでネットワークから更新します。オフラインでもエンタイトルメントの確認は高速です。

必要な場合に最新の値を取得する

サーバー側で権限を付与した後(例:サポート担当者がプロモーションを発行した後)に使います。

val fresh = Purchases.sharedInstance.awaitCustomerInfo(
    fetchPolicy = CacheFetchPolicy.FETCH_CURRENT
)
状態に応じた UI を表示する

アクセス権は isActive で判定し、その他のフィールドで状況を把握します。

fun updateUI(entitlement: EntitlementInfo?) {
    if (entitlement == null || !entitlement.isActive) {
        showSubscribeScreen(); return
    }
    showPremiumContent()
    when {
        entitlement.billingIssueDetectedAt != null -> showBillingIssueWarning()
        entitlement.unsubscribeDetectedAt != null ->
            entitlement.expirationDate?.let { showExpiryNotice(it) }
        !entitlement.willRenew -> showNonRenewingNotice()
    }
}
状態に応じたメッセージのガイド
有効なエンタイトルメントのシグナル表示するメッセージ
billingIssueDetectedAt != null支払いの問題が発生しました。お支払い方法を更新してください
unsubscribeDetectedAt != nullexpirationDate にアクセス権が終了します
willRenew == false(他のシグナルがない場合)今回の期間終了後は更新されません
periodType == TRIAL または INTROトライアルまたは導入価格が適用されています
複数デバイスでユーザーを識別する
val result = Purchases.sharedInstance.awaitLogIn("your_user_id")
val customerInfo = result.customerInfo
val createdNewUser = result.created

awaitLogIn() は匿名購入を識別済みユーザーに統合します。logOut() は新しい匿名セッションを開始します。

フェーズ 4:確認

CustomerInfo の更新をリッスンする

リスナーを登録すると、手動でポーリングしなくても、購入、復元、バックグラウンド更新に UI が反応します。

Purchases.sharedInstance.updatedCustomerInfoListener =
    UpdatedCustomerInfoListener { info ->
        val active = info.entitlements["pro_access"]?.isActive == true
        updateAccessGate(active)
    }

SDK の起動時にキャッシュがヒットし、変更がない場合、リスナーは呼び出されません。リスナーの設定に加えて、起動時には必ず awaitCustomerInfo() を呼び出してください。

テストマトリクス

各ケースを確認し、UI が正しく応答することを確かめます。

ケース期待される isActive期待される UI
初回購入trueプレミアムコンテンツ
猶予期間(請求の問題があるが、引き続き利用可能)trueプレミアムコンテンツ + 請求に関する警告
キャンセル済み、expirationDate より前trueプレミアムコンテンツ + 有効期限のお知らせ
保留中false購読画面
一時停止中false購読画面
期限切れfalse購読画面
保留中(まだ支払いなし)false購読画面
確認項目
  • 購入後にリスナーが呼び出されたとき、アクセス制御が正しく切り替わること。
  • バックエンドで付与された場合(プロモーション、返金、サポート対応)に、FETCH_CURRENT が CustomerInfo を更新すること。
  • logOut() の後、CustomerInfo に匿名ユーザーが反映され、isActive がそれに応じてリセットされること。
  • オフラインで起動した場合でも、ネットワークを呼び出さずにキャッシュされた CustomerInfo を返し、アクセスを制御すること。

参考資料

コメント