关于 rc-error-handling
面向 Android 开发者的 RevenueCat SDK 错误处理技能,涵盖购买及相关调用的异常选择和错误码分支。还说明如何映射用户提示,并避免重复添加 SDK 已处理的重试逻辑。
主要功能
- 01为 SDK 调用选择异常类型
- 02按稳定错误码处理问题
- 03区分用户取消与购买失败
- 04将技术错误映射为用户提示
- 05避免重复添加重试循环
适用场景
- 01处理已取消或待处理的购买
- 02应对网络或商店错误
- 03显示映射后的提示而不暴露技术日志
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ revenuecat/ ai-toolkit --skill rc-error-handling安装后在 Claude Code 中输入/rc-error-handling确认已加载。
详细介绍
错误处理
阶段 1:理解
使用原生 Google Play Billing 时,你需要枚举每个 BillingResponseCode,将它们分为可重试和不可重试两组,并构建退避重试逻辑。RevenueCat 将这些错误归并为一种你需要处理的类型:PurchasesError。
public class PurchasesError(
val code: PurchasesErrorCode,
val underlyingErrorMessage: String? = null,
) {
val message: String // technical description, for logs
}
你需要依赖的关键信息:
PurchasesErrorCode是跨平台枚举,包含稳定且易读的错误码。error.message是技术信息字符串,应写入日志,而不是显示在 UI 中。awaitPurchase()会抛出PurchasesTransactionException,其中包含userCancelled: Boolean标志。- 其他所有
await*调用(awaitOfferings、awaitGetProducts、awaitCustomerInfo、awaitRestore)都会抛出PurchasesException。 - SDK 已在内部重试临时性账单和网络故障。任何传递到你这里的错误都表示 SDK 已用尽重试次数。不要自行添加退避重试循环。你只需实现一种重试:由用户触发的“再试一次”按钮。
阶段 2:规划
在编写 catch 块之前,先确定以下三点:
- 你要包装哪个
await*调用?这决定了异常类型。 - 哪些错误码需要特殊处理?其他情况都归入通用分支。
- 每个已处理的错误码对应什么面向用户的文案?
使用此表对 PurchasesErrorCode 值进行分类,并选择相应的用户体验反馈。
| 错误码 | 含义 | 处理方式 |
|---|---|---|
PurchaseCancelledError | 用户退出了流程 | 不执行任何操作。userCancelled 也为 true。 |
ProductAlreadyPurchasedError | 用户已拥有该产品 | 刷新 CustomerInfo 并检查权益。 |
PaymentPendingError | 购买进入待处理状态 | 显示待处理提示。等待 UpdatedCustomerInfoListener。 |
NetworkError | 请求因网络连接问题而失败 | 提示用户重试。 |
StoreProblemError | Google Play 出现问题 | 提示用户重试或更新 Play Store。 |
PurchaseNotAllowedError | 设备或账号无法进行购买 | 显示说明性消息。 |
IneligibleError | 用户不符合优惠条件 | 改为显示基础方案。 |
异常类型选择:
| 调用 | 要捕获的异常 | 是否提供 userCancelled? |
|---|---|---|
awaitPurchase() | PurchasesTransactionException | 是 |
awaitRestore() | PurchasesException | 否 |
awaitOfferings() | PurchasesException | 否 |
awaitGetProducts() | PurchasesException | 否 |
awaitCustomerInfo() | PurchasesException | 否 |
阶段 3:执行
购买错误
先检查 userCancelled,如果为真则直接静默返回。然后根据 error.code 分支处理。
try {
val result = Purchases.sharedInstance.awaitPurchase(params)
handleSuccess(result.customerInfo)
} catch (e: PurchasesTransactionException) {
if (e.userCancelled) return
when (e.error.code) {
PurchasesErrorCode.PaymentPendingError -> showPendingMessage()
PurchasesErrorCode.ProductAlreadyPurchasedError -> {
val info = Purchases.sharedInstance.awaitCustomerInfo()
handleSuccess(info)
}
PurchasesErrorCode.NetworkError -> showRetryDialog()
else -> showGenericError(userFacingMessage(e.error))
}
}
非购买错误
捕获 PurchasesException 并根据错误码分支处理。有离线或缓存回退方案时,请使用这些方案。
try {
val offerings = Purchases.sharedInstance.awaitOfferings()
displayOfferings(offerings)
} catch (e: PurchasesException) {
when (e.error.code) {
PurchasesErrorCode.NetworkError -> showOfflineFallback()
else -> logError(e.error)
}
}
将错误码映射为面向用户的文案
使用单个映射函数。绝不要将 e.error.message 传递给 UI。
fun userFacingMessage(error: PurchasesError): String = when (error.code) {
PurchasesErrorCode.PurchaseCancelledError -> ""
PurchasesErrorCode.NetworkError ->
"Please check your internet connection and try again."
PurchasesErrorCode.StoreProblemError ->
"There was a problem with Google Play. Please try again."
PurchasesErrorCode.ProductAlreadyPurchasedError ->
"You already have this subscription."
PurchasesErrorCode.PaymentPendingError ->
"Your payment is being processed. We'll notify you when it completes."
else -> "Something went wrong. Please try again."
}
检查清单
awaitPurchase使用PurchasesTransactionException,其他调用使用PurchasesException。- 在根据
error.code分支处理前,先检查userCancelled。 - 对
PaymentPendingError、ProductAlreadyPurchasedError和NetworkError使用相应的专用处理流程。 - 记录
error.message,并向用户显示从userFacingMessage映射得到的文案。 - 没有在 SDK 调用周围添加重试循环。重试只能由用户主动发起。
参考资料
评论
支持 Markdown