关于 rc-purchase-flow
rc-purchase-flow 面向 Android 开发者,说明如何用 RevenueCat SDK 完成购买、读取权益并处理异常。内容还涵盖交易数据检查及重装或更换设备后的购买恢复。
主要功能
- 01从 Offering 获取购买套餐
- 02执行购买并按权益状态开放访问
- 03处理取消与交易异常
- 04查看交易级数据
- 05恢复已购内容并检查权益
适用场景
- 01在付费墙中购买订阅或一次性产品
- 02根据 CustomerInfo 控制高级功能访问
- 03将交易数据用于日志或自有后端
- 04在重装或换设备后恢复购买
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ revenuecat/ ai-toolkit --skill rc-purchase-flow安装后在 Claude Code 中输入/rc-purchase-flow确认已加载。
详细介绍
购买流程
在 Android 上,通过 RevenueCat 购买只需两行代码。SDK 会处理计费参数、Play 购买界面、购买令牌往返、服务端验证和确认。你只需决定传入哪个套餐,以及如何处理返回的权益。
阶段 1:了解 awaitPurchase() 的作用
调用一次 Purchases.sharedInstance.awaitPurchase(params),底层会执行六个步骤。你无需编写其中任何步骤。
| 步骤 | 执行内容 |
|---|---|
| 1 | 根据你的 Package,使用正确的 ProductDetailsParams 构建 BillingFlowParams |
| 2 | 针对你传入的 activity 调用 BillingClient.launchBillingFlow() |
| 3 | 挂起,直到收到 PurchasesUpdatedListener 的结果 |
| 4 | 如果结果为 OK,则将 Play 购买令牌发送到 RevenueCat 后端 |
| 5 | 后端通过 purchases.subscriptionsv2.get 或 purchases.products.get 进行验证 |
| 6 | SDK 会在 Google 规定的 3 天期限内确认(订阅或非消耗型商品)或消耗(消耗型商品) |
该调用会返回 PurchaseResult(storeTransaction, customerInfo)。可重试的失败会自动重试。
如需查看六步流程图和完整说明,请参阅 revenuecat.com 上的购买流程章节。
阶段 2:准备套餐
购买前,你需要从 offerings 中获取一个 Package。获取 offerings,让 UI 选择一个套餐,并保留 activity。
val offerings = Purchases.sharedInstance.awaitOfferings()
val pkg = offerings.current?.monthly ?: return
如果你需要指定优惠,而不是使用默认优惠,请解析一个 SubscriptionOption,并将它传给 PurchaseParams.Builder,而不是传入套餐。
val option = pkg.product.subscriptionOptions
?.firstOrNull { it.tags.contains("promo_50_off") }
?: pkg.product.defaultOption
?: return
对于欧盟的个性化定价,请在构建器上链式调用 .isPersonalizedPrice(true),以便 Play 显示定制价格提示。
阶段 3:执行购买
构建参数,等待购买完成,读取 customerInfo 以控制访问权限,并处理两个预期的错误分支。
try {
val result = Purchases.sharedInstance.awaitPurchase(
PurchaseParams.Builder(activity, pkg).build()
)
val customerInfo = result.customerInfo
if (customerInfo.entitlements["pro"]?.isActive == true) {
navigateToApp()
}
} catch (e: PurchasesTransactionException) {
when {
e.userCancelled -> { /* backed out, do nothing */ }
e.error.code == PurchasesErrorCode.ProductAlreadyPurchasedError ->
showMessage("You already have this subscription")
else -> showError(e.error.message)
}
}
此代码块的规则:
PurchaseResult是@Poko。请通过result.customerInfo和result.storeTransaction访问字段。不要使用val (transaction, customerInfo) = result解构。customerInfo.entitlements["<id>"]?.isActive == true是访问权限判断条件。不要检查storeTransaction来决定是否授予访问权限。awaitPurchase唯一会抛出的异常类型是PurchasesTransactionException。请捕获该异常,先检查userCancelled,再检查e.error.code。- 用户取消不应作为错误提示。请忽略该情况。
如果你更喜欢使用回调而非协程,purchaseWith(params, onError, onSuccess) 是等效的入口。
阶段 4:仅在需要时检查 StoreTransaction
result.storeTransaction 可用,但通常不会用到。customerInfo 才是权益的事实来源。如果你需要交易级数据用于日志记录或自有后端:
| 字段 | 类型 | 说明 |
|---|---|---|
orderId | String? | 恢复的购买为 Null |
purchaseToken | String | 原始 Play 购买令牌 |
productIds | List<String> | 交易中的商品 ID |
purchaseTime | Long | Epoch 毫秒 |
type | ProductType | SUBS 或 INAPP |
阶段 5:重新安装或更换设备后恢复购买
恢复购买会运行 queryPurchasesAsync(),将找到的所有购买发送到 RevenueCat,并返回最新的 CustomerInfo。请像购买完成后一样控制访问权限。
try {
val customerInfo = Purchases.sharedInstance.awaitRestore()
if (customerInfo.entitlements["pro"]?.isActive == true) {
navigateToApp()
} else {
showMessage("No active purchases found")
}
} catch (e: PurchasesException) {
showError(e.error.message)
}
请注意异常类型。awaitRestore() 会抛出 PurchasesException,而不是 PurchasesTransactionException。由于不会显示计费界面,因此无需检查 userCancelled 标志。
异常类型一览
| 调用 | 抛出的异常 | 是否包含 userCancelled? |
|---|---|---|
awaitPurchase(params) | PurchasesTransactionException | 是 |
awaitRestore() | PurchasesException | 否 |