rc-subscriptions について
Android 開発者向けの RevenueCat サブスクリプション連携スキルです。Google Play の階層を RevenueCat のオブジェクトに対応づけ、購入対象の選び方を説明します。
主な機能
- 01Google Play と RevenueCat のオブジェクト対応
- 02Offering と購入可能な Package の取得
- 03タグまたは ID によるオファー選択
- 04トライアルと初回価格の表示
- 05エンタイトルメントによるアクセス確認
活用シーン
- 01固定または動的なサブスクリプション paywall の構築
- 02対象ユーザーへのウィンバックオファー表示
- 03トライアル期間と価格フェーズの表示
- 04購入後のユーザーアクセス確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ revenuecat/ ai-toolkit --skill rc-subscriptionsインストール後、Claude Code で/rc-subscriptionsを入力して読み込まれたか確認します。
詳細
RevenueCat を使用した Android のサブスクリプション
Google Play では、サブスクリプションは「サブスクリプション」「ベースプラン」「オファー」の 3 層構造で提供されます。RevenueCat では、この階層をダッシュボードで設定する、よりフラットなモデルである「オファリング」「パッケージ」「SubscriptionOption」にまとめています。Offering を取得して Package を選び、ほとんどのフローでは SDK に適切な SubscriptionOption を選択させます。
フェーズ 1:理解する
Google Play と RevenueCat の対応関係は次のとおりです。
| Google Play | RevenueCat |
|---|---|
| サブスクリプション(product ID) | StoreProduct |
| ベースプラン | SubscriptionOption(ベースプラン) |
| オファー | SubscriptionOption(オファー) |
| ダッシュボードでまとめたベースプランのグループ | Offering 内の Package |
使用する主な型は次のとおりです。
Offering:ダッシュボードで設定するPackageオブジェクトのグループです。offerings.currentは、デフォルトで表示する Offering です。Package:購入可能な枠(月次、年次、週次、カスタム)です。product: StoreProductを公開します。StoreProduct:Google Play のサブスクリプション商品です。subscriptionOptions: List<SubscriptionOption>?とdefaultOptionを持ちます。SubscriptionOption:ベースプランまたはオファーです。pricingPhases、tags、idを持ちます。PricingPhase:1 つの課金区分(初回トライアル、初回価格、または継続課金)です。billingPeriod、price、offerPaymentMode、recurrenceModeを持ちます。
完全な Offering 階層と、エンタイトルメントの確認に使用する CustomerInfo 階層を並べたオブジェクトモデル図については、revenuecat.com のサブスクリプションに関する章をご覧ください。
フェーズ 2:計画する
コードを書く前に、ペイウォールをオブジェクトモデルに対応付けます。次の 3 つの質問に答えてください。
2.1 ペイウォールで使用する Offering はどれですか?
- デフォルトのペイウォール:
offerings.currentを使用します。これはダッシュボードで current に設定された Offering であり、標準的な選択肢です。 - 実験またはセグメント固有のペイウォール:
offerings.all["experiment-a"]を取得します。どの商品を表示するかはダッシュボードで管理できるため、カタログを変更してもアプリのアップデートは不要です。
2.2 どの Package を表示しますか?
アクセス方法は 2 つあります。レイアウトに合った方法を選んでください。
| パターン | API | 使用する場面 |
|---|---|---|
| 名前付きスロット | offering.monthly、offering.annual、offering.weekly | 期間が決まっている固定ペイウォール |
| 反復処理 | offering.availablePackages | 動的なレイアウト、期間が不明な場合、またはカスタムのパッケージタイプ |
標準の PackageType 値は MONTHLY、ANNUAL、WEEKLY、TWO_MONTH、THREE_MONTH、SIX_MONTH、LIFETIME です。それ以外は PackageType.CUSTOM です。
2.3 ペイウォールでは特定のオファーが必要ですか?それともデフォルトで問題ありませんか?
| 状況 | PurchaseParams に渡すもの |
|---|---|
| 標準的なペイウォールで、ユーザーが適用可能な最適なオファーを自動的に受け取る | Package |
| 特定のオファーが必要(引き戻し、プロモーション、選択されたタグ) | SubscriptionOption |
SDK の defaultOption のロジックは次のとおりです。
"rc-ignore-offer"または"rc-customer-center"のタグが付いたオプションを除外します。- 無料トライアル期間が最も長いオプション、または最初の課金区分の価格が最も安いオプションを選びます。
- 該当するオファーがない場合は、ベースプランにフォールバックします。
SDK はトライアルの適用可否を絞り込みません。Google Play はユーザーが適用対象となるオファーのみを返すため、すでに無料トライアルを利用したユーザーの場合、そのオプションは subscriptionOptions に表示されず、ベースプランがデフォルトになります。
フェーズ 3:実行する
3.1 Offerings を取得して Package を選ぶ
val offerings = Purchases.sharedInstance.awaitOfferings()
val offering = offerings.current ?: return
val monthly = offering.monthly ?: return
val product = monthly.product
val price = product.price.formatted
val period = product.period?.iso8601 // "P1M", "P1Y", null for one time
動的なリストの場合:
for (pkg in offering.availablePackages) {
render(pkg.product.title, pkg.product.price.formatted, pkg.packageType)
}
3.2 デフォルトのオプションで購入する
ペイウォールに Package を表示し、SDK に最適なオファーを選ばせる場合は、Package を直接渡します。
val params = PurchaseParams.Builder(activity, monthly).build()
val result = Purchases.sharedInstance.awaitPurchase(params)
3.3 特定のオファーについて subscriptionOptions を詳しく確認する
タグまたはオファー ID でオファーを指定するペイウォール(引き戻しオファーなど)で使用します。
val product = offering.monthly?.product ?: return
val winBack = product.subscriptionOptions
?.firstOrNull { it.tags.contains("win-back") }
val option = winBack ?: product.defaultOption ?: return
val params = PurchaseParams.Builder(activity, option).build()
対象のオファーがない場合(たとえば、ユーザーが適用対象でない場合)でもペイウォールが機能するよう、必ず defaultOption にフォールバックしてください。
3.4 pricingPhases からトライアルと初回限定価格を表示する
最初の PricingPhase がある場合は、トライアル価格または初回限定価格です。トライアルを判定するには offerPaymentMode を使用します。
val option = pkg.product.defaultOption ?: return
val first = option.pricingPhases.first()
val isTrial = first.offerPaymentMode == OfferPaymentMode.FREE_TRIAL
billingPeriod.value は期間の単位における数であり、日数ではありません。期間が P1W の場合、value = 1、unit = WEEK となります。両方のフィールドを使ってラベルを作成してください。
val p = first.billingPeriod
val label = when (p.unit) {
Period.Unit.DAY -> "${p.value} day"
Period.Unit.WEEK -> "${p.value} week"
Period.Unit.MONTH -> "${p.value} month"
Period.Unit.YEAR -> "${p.value} year"
else -> p.iso8601
}
3.5 プリペイドプラン
プリペイドのベースプランには、同じ SubscriptionOption API を使用します。pricingPhases では RecurrenceMode.NON_RECURRING が返されます。プリペイドプランで保留中の購入を受け付けるには、設定時にフラグを有効にしてください。
PurchasesConfiguration.Builder(context, apiKey)
.pendingTransactionsForPrepaidPlansEnabled(true)
.build()
3.6 購入後にアクセス権を確認する
エンタイトルメントを使用することをおすすめします。猶予期間、アカウント保留、残りの利用期間がある状態でのキャンセルなどを含む、サーバーで計算されたアクセス状態が反映されます。
val info = result.customerInfo
val isPro = info.entitlements["pro"]?.isActive == true
生のプロダクト ID が必要な場合は、customerInfo.activeSubscriptions を使用してください。"subscriptionId:basePlanId" 形式のエントリを含む Set<String> が返されます。
判断のまとめ
| 質問 | 回答 |
|---|---|
| プロダクトを取得するにはどうすればよいですか? | Purchases.sharedInstance.awaitOfferings() を呼び出し、その後 offerings.current を使用します。 |
| 期間を表示するにはどうすればよいですか? | offering.monthly/annual/weekly を使用するか、availablePackages を反復処理します。 |
| 購入するにはどうすればよいですか? | Package を PurchaseParams に渡し、defaultOption を適用します。 |
| 特定のオファーを指定するにはどうすればよいですか? | product.subscriptionOptions をタグまたは ID で絞り込み、SubscriptionOption を渡します。 |
| 無料トライアルを判定するにはどうすればよいですか? | pricingPhases.first().offerPaymentMode == OfferPaymentMode.FREE_TRIAL を確認します。 |
| アクセス権を確認するにはどうすればよいですか? | customerInfo.entitlements["<id>"]?.isActive を確認します。 |