revenuecat-purchase-flow

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

revenuecat-purchase-flow: buy a package and restore purchases

revenuecat-purchase-flow:购买套餐与恢复购买记录

Use this skill when the user wants to complete the purchase side of RevenueCat: fetch offerings, call
purchase
, deal with cancellation and errors, and expose a "Restore" action. It does not cover rendering a paywall UI (that lives in
revenuecat-paywall
) or gating features (that lives in
revenuecat-entitlements-gate
).
当用户需要完成RevenueCat的购买相关操作时使用此技能:获取产品服务、调用
purchase
方法、处理取消操作与错误,并提供“恢复”功能。此技能不包含付费墙UI的渲染(该功能在
revenuecat-paywall
中)或功能权限控制(该功能在
revenuecat-entitlements-gate
中)。

1. Detect the platform

1. 检测平台

Inspect the working directory and pick the first match, from top to bottom:
  1. React Native:
    package.json
    has a
    react-native-purchases
    entry, or
    react-native
    as a dependency → read
    platforms/react-native.md
    . If
    expo
    is also a dependency, note it as an Expo project.
  2. Flutter:
    pubspec.yaml
    exists at the project root → read
    platforms/flutter.md
    .
  3. Kotlin Multiplatform:
    build.gradle.kts
    contains a
    kotlin { … }
    multiplatform source sets block, or depends on
    com.revenuecat.purchases:purchases-kmp*
    → read
    platforms/kmp.md
    .
  4. Android (native):
    build.gradle(.kts)
    applies
    com.android.application
    (and is not KMP) → read
    platforms/android.md
    .
  5. iOS (native):
    Package.swift
    ,
    *.xcodeproj
    ,
    *.xcworkspace
    , or
    Podfile
    at the project root → read
    platforms/ios.md
    .
If several match (e.g. an
ios/
folder inside a Flutter project), pick the outermost project, the one that owns the build. If still ambiguous, ask the user which platform they want to configure.
检查工作目录,从上到下选择第一个匹配项:
  1. React Native
    package.json
    中包含
    react-native-purchases
    条目,或依赖
    react-native
    → 查看
    platforms/react-native.md
    。如果同时依赖
    expo
    ,则标记为Expo项目。
  2. Flutter:项目根目录存在
    pubspec.yaml
    → 查看
    platforms/flutter.md
  3. Kotlin Multiplatform
    build.gradle.kts
    包含
    kotlin { … }
    多平台源码集块,或依赖
    com.revenuecat.purchases:purchases-kmp*
    → 查看
    platforms/kmp.md
  4. Android(原生)
    build.gradle(.kts)
    应用了
    com.android.application
    (且非KMP项目)→ 查看
    platforms/android.md
  5. iOS(原生):项目根目录存在
    Package.swift
    *.xcodeproj
    *.xcworkspace
    Podfile
    → 查看
    platforms/ios.md
如果存在多个匹配项(例如Flutter项目内包含
ios/
文件夹),请选择最外层的项目,即拥有构建权限的项目。若仍存在歧义,请询问用户需要配置哪个平台。

2. Shared concepts (all platforms)

2. 通用概念(全平台)

  • Flow. Call
    getOfferings()
    , pick a
    Package
    from the current offering, call
    purchase(package)
    . When it completes successfully, the returned
    customerInfo
    already reflects the purchase. Read
    customerInfo.entitlements.active["<id>"]
    to confirm access.
  • User cancellation is not an application error. Each SDK surfaces it differently: iOS throws a
    purchaseCancelledError
    code, Android throws a
    PurchasesException
    with
    PurchasesErrorCode.PurchaseCancelledError
    , Flutter surfaces a
    PlatformException
    with that same code, React Native sets
    e.userCancelled === true
    . Return silently in this case. Do not show an alert.
  • Errors worth messaging. Payment declined, network errors, store unavailable, receipt already in use. Everything else should be logged and let the user try again. Never silently succeed when the purchase actually failed.
  • Do not unlock content inside the purchase callback. Refresh customer info and let your entitlements listener (see
    revenuecat-entitlements-gate
    ) flip the gated UI. This keeps one source of truth for access and avoids drift between the purchase path and the restore path.
  • restorePurchases()
    is a user action, not an automatic step.
    It asks the store for the current receipt and syncs it to RevenueCat. Expose it from a visible "Restore purchases" button on the paywall and/or settings screen. Legal requirements on iOS mandate such a button.
  • One purchase at a time. Disable the paywall buy buttons while a purchase is in flight to prevent double charges.
  • 流程:调用
    getOfferings()
    ,从当前产品服务中选择一个
    Package
    ,调用
    purchase(package)
    。操作成功完成后,返回的
    customerInfo
    已反映购买情况。读取
    customerInfo.entitlements.active["<id>"]
    确认访问权限。
  • 用户取消不属于应用错误:各SDK的表现形式不同:iOS抛出
    purchaseCancelledError
    错误码,Android抛出带有
    PurchasesErrorCode.PurchaseCancelledError
    PurchasesException
    ,Flutter返回带有相同错误码的
    PlatformException
    ,React Native设置
    e.userCancelled === true
    。这种情况下应静默返回,不要显示提示框。
  • 需要提示用户的错误:支付拒绝、网络错误、商店不可用、收据已被使用。其他所有错误应仅记录日志并允许用户重试。购买实际失败时绝不能静默标记为成功。
  • 不要在购买回调中解锁内容:刷新客户信息,让权限监听器(参考
    revenuecat-entitlements-gate
    )切换受权限控制的UI。这样可以保持访问权限的单一数据源,避免购买路径与恢复路径之间出现数据不一致。
  • restorePurchases()
    是用户主动操作,而非自动步骤
    :它会向商店请求当前收据并同步到RevenueCat。在付费墙和/或设置页面上提供一个可见的“恢复购买记录”按钮。iOS的法律要求强制提供此类按钮。
  • 同一时间仅处理一次购买:购买进行中时禁用付费墙的购买按钮,防止重复扣费。

3. Implementation

3. 实现

Read the platform file that matches detection:
  • platforms/ios.md
  • platforms/android.md
  • platforms/kmp.md
  • platforms/flutter.md
  • platforms/react-native.md
Each platform file contains a complete purchase function and a restore function.
查看与检测结果匹配的平台文件:
  • platforms/ios.md
  • platforms/android.md
  • platforms/kmp.md
  • platforms/flutter.md
  • platforms/react-native.md
每个平台文件都包含完整的购买函数和恢复函数。

4. Verify

4. 验证

Do not claim the flow works until:
  1. A sandbox purchase of the current offering's package succeeds end to end, and the user's entitlement flips to active.
  2. Cancelling the store sheet does not show an error alert and does not leave the UI in a loading state.
  3. A second purchase attempt for the same active subscription is handled cleanly (StoreKit / Play Billing will surface a
    productAlreadyPurchased
    /
    receiptAlreadyInUse
    path; the flow should not crash).
  4. The restore button, on a fresh install signed in to the same store account, restores the entitlement and updates the UI.
满足以下条件后才能确认流程可用:
  1. 当前产品服务套餐的沙箱购买能够端到端成功,且用户权限切换为激活状态。
  2. 取消商店界面不会显示错误提示框,也不会让UI停留在加载状态。
  3. 针对同一激活订阅的第二次购买尝试能够被正常处理(StoreKit/Play Billing会返回
    productAlreadyPurchased
    /
    receiptAlreadyInUse
    状态;流程不应崩溃)。
  4. 在全新安装的设备上登录同一商店账号,点击恢复按钮后能够恢复权限并更新UI。