mcpField
R
rc-error-handling

rc-error-handling

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

关于 rc-error-handling

面向 Android 开发者的 RevenueCat SDK 错误处理技能,涵盖购买及相关调用的异常选择和错误码分支。还说明如何映射用户提示,并避免重复添加 SDK 已处理的重试逻辑。

主要功能

  1. 01为 SDK 调用选择异常类型
  2. 02按稳定错误码处理问题
  3. 03区分用户取消与购买失败
  4. 04将技术错误映射为用户提示
  5. 05避免重复添加重试循环

适用场景

  1. 01处理已取消或待处理的购买
  2. 02应对网络或商店错误
  3. 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 块之前,先确定以下三点:

  1. 你要包装哪个 await* 调用?这决定了异常类型。
  2. 哪些错误码需要特殊处理?其他情况都归入通用分支。
  3. 每个已处理的错误码对应什么面向用户的文案?

使用此表对 PurchasesErrorCode 值进行分类,并选择相应的用户体验反馈。

错误码含义处理方式
PurchaseCancelledError用户退出了流程不执行任何操作。userCancelled 也为 true。
ProductAlreadyPurchasedError用户已拥有该产品刷新 CustomerInfo 并检查权益。
PaymentPendingError购买进入待处理状态显示待处理提示。等待 UpdatedCustomerInfoListener。
NetworkError请求因网络连接问题而失败提示用户重试。
StoreProblemErrorGoogle 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