mcpField
R
rc-subscription-states

rc-subscription-states

github.com/revenuecat开发76643 次安装1 天前更新
代码仓库

关于 rc-subscription-states

面向 Android 开发者的 RevenueCat 订阅状态处理技能,介绍如何判断用户是否有权访问功能并更新界面。内容涵盖权益字段、缓存或实时获取的 CustomerInfo,以及更新监听器。

主要功能

  1. 01依据权益激活状态控制访问
  2. 02读取续订、到期和账单状态
  3. 03使用缓存或实时获取的 CustomerInfo
  4. 04通过客户信息监听器更新界面
  5. 05处理已识别用户与匿名用户

适用场景

  1. 01根据订阅访问权限显示高级内容
  2. 02展示账单问题或到期提示
  3. 03服务器端授权后刷新访问状态
  4. 04购买或恢复后同步访问界面

安装

复制下面的命令,在终端中运行。

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

安装后在 Claude Code 中输入/rc-subscription-states确认已加载。

详细介绍

Subscription States

在 Android 上使用 CustomerInfo 和 EntitlementInfo 判断用户是否有权限,并驱动能够感知状态的 UI。

Phase 1: Discover

编写代码前,确认你实际要检查的内容。

  • 哪个权益标识符控制此功能?(例如 pro_access)
  • 你只需要一个简单的权限布尔值,还是也需要说明用户拥有或没有权限的原因(付款问题、已取消但仍处于付费期、已暂停)?
  • 你需要缓存值(速度快,但可能过时),还是需要最新获取的值(以服务器为准)?
  • 你是在启动时刷新一次 UI,还是要响应实时变化(购买、恢复、后台刷新)?

如果你只需要检查是否有权限,只需使用 isActive。其他内容都是可选的上下文信息。

Phase 2: Plan

Google 的七种状态与 RevenueCat 的布尔值

使用 Google Play Developer API 自行实现追踪器,意味着要映射七种订阅状态,并决定哪些状态授予权限。

Google 状态是否授予权限?
ACTIVE是
IN_GRACE_PERIOD是
CANCELED(expirationDate 之前)是
ON_HOLD否
PAUSED否
EXPIRED否
PENDING否

RevenueCat 会在后端根据 Google SubscriptionPurchaseV2 资源计算此结果,并将结果作为一个字段提供:EntitlementInfo.isActive。你读取一个布尔值即可,无需自行实现状态机。

读取什么,以及何时读取
需求字段
用户现在是否有权限?entitlement.isActive
订阅是否会在周期结束时续订?entitlement.willRenew
付费权限何时结束?entitlement.expirationDate
当前是试用期、入门优惠期、预付费期还是正常周期?entitlement.periodType
是否存在付款问题?entitlement.billingIssueDetectedAt
用户是否已取消,但仍有剩余时间?entitlement.unsubscribeDetectedAt
哪个商店授予了此权益?entitlement.store
判断规则
  • 仅在 isActive == true 时开放功能权限,不要依赖其他条件。
  • 使用 billingIssueDetectedAt != null 显示修复付款问题的提示。
  • 使用 unsubscribeDetectedAt != null 和 expirationDate,在权限仍有效时显示续订提醒。
  • 在没有付款问题且没有明确取消时间戳的情况下,使用 !willRenew 显示不续订通知。

Phase 3: Execute

读取 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 != null权限将于 expirationDate 结束
willRenew == false(没有其他信号)此周期结束后不会续订
periodType == TRIAL 或 INTRO正在使用试用期或入门优惠价格
为多设备场景识别用户
val result = Purchases.sharedInstance.awaitLogIn("your_user_id")
val customerInfo = result.customerInfo
val createdNewUser = result.created

awaitLogIn() 会将匿名购买记录合并到已识别的用户账户中。logOut() 会开始一个全新的匿名会话。

Phase 4: Verify

监听 CustomerInfo 更新

注册监听器,让 UI 能够响应购买、恢复和后台刷新,而无需手动轮询。

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

如果 SDK 启动时命中缓存且内容未发生变化,监听器不会触发。除了设置监听器外,启动时还应始终调用 awaitCustomerInfo()。

测试矩阵

逐一检查每种情况,并确认 UI 响应正确。

情况预期 isActive预期 UI
新购买true高级内容
宽限期(账单问题,但仍有权限)true高级内容 + 账单警告
已取消,但尚未到 expirationDatetrue高级内容 + 到期通知
暂停计费false订阅页面
已暂停false订阅页面
已过期false订阅页面
待处理(尚未付款)false订阅页面
检查要点
  • 购买后监听器触发时,访问权限门控会正确切换。
  • 后端授予权限(促销、退款、客服操作)后,FETCH_CURRENT 会更新 CustomerInfo。
  • 调用 logOut() 后,CustomerInfo 会反映匿名用户状态,isActive 也会相应重置。
  • 离线启动时仍会返回缓存的 CustomerInfo,并在不发起网络请求的情况下控制访问权限。

参考资料

评论

支持 Markdown