mcpField
R
rc-plan-changes

rc-plan-changes

github.com/revenuecat開発76641 回インストール今日更新
リポジトリ

rc-plan-changes について

RevenueCat で Google Play の有効なサブスクリプションを変更する Android 開発者向けガイドです。置き換えモード、CustomerInfo からの現行商品取得、変更後の状態確認を説明します。

主な機能

  1. 01Google の置き換えモード選択
  2. 02CustomerInfo から商品 ID を取得
  3. 03アップグレードとダウングレード時期の説明
  4. 04RevenueCat によるトークンチェーン処理
  5. 05変更後のエンタイトルメント確認

活用シーン

  1. 01月額プランから年額プランへの変更
  2. 02更新時に適用するダウングレード
  3. 03無料トライアルから有料プランへの移行

インストール

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

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

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

詳細

RevenueCat を使って Android のプランを変更する

ユーザーがすでに有効な Google Play サブスクリプションを持っており、別の SKU への変更(アップグレード、ダウングレード、クロスグレード、またはトライアルからの切り替え)が必要な場合に、このスキルを使用します。RevenueCat は単一の PurchaseParams ビルダーを通じて Google の置換モードを公開し、linkedPurchaseToken のチェーンをサーバー側で解決するため、トークンをつなぐコードを自分で書く必要はありません。

フェーズ 1:前提条件

プラン変更を実行する前に、次の点を確認してください。

  • 置き換える対象として、ユーザーが有効な Google Play サブスクリプションを 1 つだけ持っていること。
  • Purchases.sharedInstance.awaitCustomerInfo() から最新の CustomerInfo を取得していること、または最近のリスナーコールバックからキャッシュ済みの値を取得していること。
  • offerings.current から対象の Package を解決済みであること(fetch-offerings スキルを参照)。
  • RevenueCat SDK 経由で、Google Play Billing Library 7+ がクラスパスに含まれていること。

ユーザーに有効なサブスクリプションがない場合は、このスキルを使用しないでください。新規購入には、代わりに make-purchase を使用してください。

フェーズ 2:計画(置換モードを選択する)

GoogleReplacementMode は Google の課金モードに 1 対 1 で対応しています。ユーザーの意図に基づいて選択してください。

シナリオモード課金への影響
標準的なアップグレード(月額から年額へ)WITH_TIME_PRORATION即時に切り替わり、残りの利用期間分が充当されます
既存の課金日を維持したアップグレードCHARGE_PRORATED_PRICE即時に切り替わり、日割り計算された料金がその場で請求されます
プリペイドプランへの、またはプリペイドプランからの切り替えCHARGE_FULL_PRICE即時に切り替わり、全額がその場で請求されます
有効な無料トライアル中のアップグレードCHARGE_PRORATED_PRICE即時に切り替わり、日割り計算された料金がその場で請求されます
ダウングレード(年額から月額へ)DEFERRED次回更新時に切り替わります

トライアル中のアップグレードで、デフォルトとして WITHOUT_PRORATION を使用しないでください。WITHOUT_PRORATION は新しいプランを即時に適用しますが、次回更新まで料金を請求しません。そのため、ユーザーは料金を支払わずにプレミアム機能を利用できてしまいます。アップグレード料金をその場で請求するには、CHARGE_PRORATED_PRICE を使用してください。

モードを指定しない場合、PurchaseParams はデフォルトで WITHOUT_PRORATION になります。毎回、モードを明示的に設定してください。

DEFERRED が有効なのはダウングレードの場合のみです。Google はアップグレードに対する遅延切り替えを拒否します。

フェーズ 3:実行

CustomerInfo から currentProductId を導出してください。ハードコードされた SKU は、ユーザーがプラン間を移行した場合に正しく動作しません。

val customerInfo = Purchases.sharedInstance.awaitCustomerInfo()

// activeSubscriptions entries are "productId:basePlanId", strip the base plan suffix
val currentProductId = customerInfo.activeSubscriptions
    .firstOrNull()
    ?.substringBefore(":")
    ?: return  // nothing active, route to make-purchase instead

val newPackage = offerings.current
    ?.availablePackages
    ?.firstOrNull { it.identifier == "premium_annual_package" }
    ?: return

val params = PurchaseParams.Builder(activity, newPackage)
    .googleProductChangeInfo(
        GoogleProductChangeInfo(
            oldProductId = currentProductId,
            replacementMode = GoogleReplacementMode.WITH_TIME_PRORATION,
        )
    )
    .build()

try {
    val result = Purchases.sharedInstance.awaitPurchase(params)
    // result.customerInfo reflects the new subscription
} catch (e: PurchasesTransactionException) {
    if (!e.userCancelled) showError(e.error.message)
}

oldProductId に関する注意事項:

  • サブスクリプションのプロダクト ID のみを渡してください。"basic_monthly:monthly_plan" を渡した場合、SDK が :monthly_plan を削除しますが、自分で切り出すほうが意図が明確です。
  • CustomerInfo.activeSubscriptions は productId:basePlanId 形式です。substringBefore(":") を使うと、正しい値を取得できます。

フェーズ 4:確認

サスペンド関数の呼び出しが戻った後、更新された CustomerInfo を読み取ります。

  • customerInfo.activeSubscriptions に新しい productId:basePlanId が含まれていること。
  • 切り替えの間も customerInfo.entitlements["pro"]?.isActive が true のままであること。SKU の文字列で UI の表示を制御しないでください。
  • DEFERRED モードの場合、次回更新まで activeSubscriptions には引き続き古いプロダクトが報告されます。RevenueCat はサーバー側で保留中の切り替えを追跡し、Google が更新の RTDN を送信した後にエンタイトルメントを切り替えます。

linkedPurchaseToken をたどるコードを書く必要はありません。RevenueCat がチェーンを解決し、古いトークンを置換済みとしてマークし、両方のトークンを同じ App User ID に関連付けます。クライアントコードはエンタイトルメントを読み取り、それを信頼します。

よくある間違い

間違い修正方法
oldProductId を定数としてハードコードするcustomerInfo.activeSubscriptions.firstOrNull()?.substringBefore(":") から導出します
"productId:basePlanId" を oldProductId として渡すsubstringBefore(":") でベースプランを切り取ります
トライアルからのアップグレードに WITHOUT_PRORATION を使うユーザーに今すぐ課金するため、CHARGE_PRORATED_PRICE を使います
アップグレードに DEFERRED を使うDEFERRED はダウングレード専用です。Google は保留中のアップグレードを拒否します
linkedPurchaseToken を追跡するバックエンドコードを書くRevenueCat がサーバー側で処理するため、そのコードは削除します
UI の状態を判断するために SKU を読み取る代わりに entitlements[...]?.isActive を読み取ります

参考資料

コメント