关于 rc-subscriptions
面向 Android 开发者的 RevenueCat 订阅集成技能,介绍如何将 Google Play 订阅层级映射到 Offerings、Packages 和 SubscriptionOptions,并选择购买项。
主要功能
- 01映射 Google Play 与 RevenueCat 对象
- 02获取 Offering 和可购买 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 通过三层层级提供订阅:Subscription、Base Plan 和 Offer。RevenueCat 将此层级封装为一种更扁平的模型,你可以在控制面板中配置:Offerings、Packages 和 SubscriptionOptions。你可以获取一个 Offering,选择一个 Package,并在大多数流程中让 SDK 为你选择合适的 SubscriptionOption。
阶段 1:了解
Google Play 与 RevenueCat 之间的映射关系:
| Google Play | RevenueCat |
|---|---|
| Subscription(产品 ID) | StoreProduct |
| Base Plan | SubscriptionOption(基础计划) |
| Offer | SubscriptionOption(优惠) |
| 在控制面板中归为一组的基础计划 | Offering 中的 Package |
你会用到的关键类型:
Offering:在控制面板中配置的一组Package对象。offerings.current是默认展示的 Offering。Package:可购买的选项(月度、年度、每周、自定义)。提供一个product: StoreProduct。StoreProduct:Google Play 订阅产品。包含subscriptionOptions: List<SubscriptionOption>?和defaultOption。SubscriptionOption:基础计划或优惠。包含pricingPhases、tags和id。PricingPhase:一个计费阶段(首次试用、首次优惠价或定期计费)。包含billingPeriod、price、offerPaymentMode和recurrenceMode。
请参阅 revenuecat.com 上的订阅章节,了解对象模型图,其中展示了完整的 Offerings 层级,以及用于检查权益的 CustomerInfo 层级。
阶段 2:规划
编写代码之前,先将付费墙映射到对象模型。回答以下三个问题。
2.1 哪个 Offering 用于付费墙?
- 默认付费墙:使用
offerings.current。这是控制面板中标记为 current 的 Offering,也是标准选择。 - 面向实验或特定细分群体的付费墙:获取
offerings.all["experiment-a"]。产品展示由控制面板决定,因此目录变更时无需更新应用。
2.2 要展示哪些 Packages?
有两种访问方式,请根据布局选择:
| 模式 | 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 生效。 |
| 如何指定特定优惠? | 按标签或 ID 筛选 product.subscriptionOptions,然后传递 SubscriptionOption。 |
| 如何检测免费试用? | 使用 pricingPhases.first().offerPaymentMode == OfferPaymentMode.FREE_TRIAL。 |
| 如何检查访问权限? | 使用 customerInfo.entitlements["<id>"]?.isActive。 |