
做过 App 内购的开发者心里都清楚:苹果一套 API,谷歌一套 API,收据验证要自己搭后端,订阅状态变更还要接 Webhook……一个订阅功能,前后端加双平台,没两周搞不定。直到 RevenueCat 出现。
如果你做过带订阅功能的 App,大概率经历过这种场景:
iOS 端接入 StoreKit,配置 SKProduct,监听支付回调,处理收据验证。Android 端来一套 BillingClient,注册 PurchasesUpdatedListener,接上 Google Play Developer API。两边都跑通了,产品经理说:"加个 A/B 测试看看年付和月付哪个转化率高。"
这时候你知道,真正的麻烦才刚刚开始。
01 内购这件事,到底有多麻烦?

先看如果不借助第三方,自己搞一套完整的内购系统需要做哪些事:
SKProductsRequest | queryProductDetailsAsync | |
SKPaymentQueue.add | launchBillingFlow | |
SKPaymentTransactionObserver | PurchasesUpdatedListener | |
两套完全不同的 API,两套回调机制,两套通知系统。如果你还做了 Web 端用 Stripe,那就是三套。
更麻烦的是维护成本:苹果每年 WWDC 可能改 StoreKit API,Google 也会更新 Billing Library。每次升级都要重新适配。核心工程师离职了,新人接手可能得啃几个月。
02 RevenueCat 是什么?
RevenueCat 做的就是一件事:把上面所有的脏活累活包了,给你一套统一的 SDK。
它的架构很简单:
你的 App → RevenueCat SDK → RevenueCat 后端 → Apple/Google API ↓ 统一的 CustomerInfo + Webhook你不需要自己管理 StoreKit 或 BillingClient 的连接生命周期,不需要自己搭收据验证服务器,不需要自己维护订阅状态机。SDK 初始化一次,后面全是调用 Purchases.sharedInstance 的几个方法。
来看看这个成绩单:
- 91,000+
App 正在使用 年处理订阅流水 $130亿+ - 99.99%
可用性 - SOC2 认证、
GDPR 合规 AWS 多可用区部署
定价方面也很良心:月收入 $2,500 以下完全免费,超过后才按使用量付费。
03 核心概念详解

RevenueCat 的核心抽象层有四个层级,从底层到顶层依次是:Product → Offering → Package → Entitlement。
3.1 四层架构总览
┌─────────────────────────────────────────────────────────┐│ Entitlement (用户权限,业务层) ││ 例:pro_access → 是否解锁高级功能 │├─────────────────────────────────────────────────────────┤│ Offering (定价页面,一组商品的集合) ││ 例:"default" → 包含月付/年付/永久 │├─────────────────────────────────────────────────────────┤│ Package (跨平台商品映射,同一逻辑商品) ││ 例:"monthly" → iOS的premium_monthly = Android的premium │├─────────────────────────────────────────────────────────┤│ Product / StoreProduct (各商店实际创建的商品) ││ 例:iOS: com.app.premium_monthly / Android: premium_m │└─────────────────────────────────────────────────────────┘3.2 Products:你在商店里实际创建的商品
这是最底层,对应你在 App Store Connect 或 Google Play Console 里真实创建的订阅商品。
- iOS 侧:
每个 Auto-Renewable Subscription 有一个 product identifier(如 com.myapp.premium_monthly),关联特定的时长和价格 - Android 侧
:结构更复杂——一个 subscription 下面可以有多个 base plan(订阅基准方案),每个 base plan 又可以有多个 offer(优惠方案)
RevenueCat 把这两者的差异封装掉了。你在 SDK 里拿到的是一个统一的 StoreProduct 对象,不用关心底层是 iOS 的 SKProduct 还是 Android 的 ProductDetails。
3.3 Offerings & Packages:业务层面的"卖什么"
Offering 是一组商品的集合,本质上就是一个"定价页面"的抽象。
你可能同时有多个 Offering:给新用户的 "default"、给老用户的 "loyalty"、节日促销的 "holiday_sale"。切换到哪个 Offering 完全由 RevenueCat 后台控制,不需要发版。
Package 则是在不同平台上代表"同一件商品"。你在 iOS 上有一个 product ID premium_monthly,在 Android 上有一个 premium_monthly,它们应该在同一个 Package 里。
Offering: "default"├── Package: "$rc_monthly" → iOS: premium_monthly, Android: premium_monthly├── Package: "$rc_annual" → iOS: premium_yearly, Android: premium_yearly└── Package: "lifetime" → iOS: premium_lifetime, Android: premium_lifetimeRevenueCat 内置了几个标准 Package 标识符:$rc_weekly、$rc_monthly、$rc_annual、$rc_six_month、$rc_three_month 等。用标准标识符的话,SDK 可以直接通过 .monthly、.annual 这样的属性访问,不需要硬编码字符串。
3.4 Entitlements:用户权限的统一抽象
Entitlement 是整个系统最巧妙的设计。
它的思想是:用户购买的是"权限",而不是某个具体的商品。一个用户可能通过月付获得 pro_access,另一个用户可能通过年付获得 pro_access,还可能有用户通过永久买断获得 pro_access。在代码里,你判断的永远只是:
if customerInfo.entitlements["pro_access"]?.isActive ==true你不需要关心用户是月付、年付还是永久。哪怕你把商品从 premium_monthly 换成 pro_monthly_v2,Entitlement 的逻辑完全不用改。
Entitlement 和 Product 的关联在 RevenueCat Dashboard 里配,一个 Entitlement 可以关联多个 Product。用户购买了任意一个关联的商品,Entitlement 就会变成 active。
3.5 举个例子:完整配置链路
1. 在 App Store Connect 创建商品 → Product ID: com.myapp.monthly, com.myapp.yearly2. 在 Google Play Console 创建商品 → Product ID: monthly_sub, yearly_sub (含 base plan)3. 在 RevenueCat Dashboard: a. Products 页面 → 商品自动同步,或手动添加 b. Offerings → 新建 "default" Offering c. 在 default 里加两个 Package: - "$rc_monthly" → 绑定 iOS com.myapp.monthly + Android monthly_sub - "$rc_annual" → 绑定 iOS com.myapp.yearly + Android yearly_sub d. Entitlements → 新建 "pro_access" e. 把 monthly Package 和 annual Package 关联到 pro_access4. 客户端代码: let offerings = await Purchases.shared.offerings() let monthly = offerings.current!.monthly // 拿到 Package let result = await Purchases.shared.purchase(package: monthly) // result.customerInfo.entitlements["pro_access"]?.isActive == true ✅这个链路虽然看起来步骤多,但大部分是一次性的配置工作。配完以后,以后改价格、调方案、加促销,全在 Dashboard 里点几下就行。
04 三端配置:RevenueCat + App Store + Google Play
开始写代码之前,有三端需要配置好。按顺序来。

4.1 RevenueCat Dashboard 配置
第一步,打开 app.revenuecat.com 注册账号。
创建 Project:
登录后创建一个 Project,给它起个名字。每个 Project 对应你的一个 App(或一套 App)。
添加平台 App:
在 Project Settings → Apps 里添加你的平台:
添加 iOS App → 系统生成一个 appl_开头的 Public API Key添加 Android App → 系统生成一个 goog_开头的 Public API Key
这两个 key 分别用在 iOS 和 Android 的 SDK 初始化中。
你还需要区分两组 API Key:
- Test Store API Key:
开发测试用,不需要连接真实商店 - Production API Key:
生产环境用,需要连接 App Store / Google Play 建议用 Build Configuration 或环境变量来切换,不要写死在代码里。
创建 Products、Offerings、Entitlements:
在 RevenueCat Dashboard 左侧菜单:
Products → + New → 输入商品 ID、时长、价格(也可以从商店自动同步) Offerings → + New → 创建 "default" → + Add Package → 选择 Package 标识符 → 绑定 Product Entitlements → + New → 创建 "pro_access" → 关联对应的 Products 或 Packages
连接商店(生产环境必需):
如果不连接商店,RevenueCat 只能用自己的 Test Store(模拟购买,不出真钱)。要上线必须连:
- 连接 App Store:
需要上传 .p8文件 + Key ID + Issuer ID(见下文 4.2) - 连接 Google Play:
需要上传 Service Account JSON Key(见下文 4.3)
在 App Settings → Store Integration 里配置。
4.2 App Store Connect 配置
创建订阅商品:
在 App Store Connect → 你的 App → 功能 → 内购项目 点 + → "自动续期订阅" 填写: - 参考名称:
对内显示的标识(如 "月度会员") - 产品 ID:
格式 com.yourcompany.yourapp.monthly - 订阅时长:
周/月/季/半年/年 - 价格:
选择价格等级(如 Tier 1 = $0.99) 创建完成后确保商品状态为"准备提交"(Ready to Submit)(无需真正提交审核),Sandbox 环境下即可测试
生成 IAP Key (.p8 文件):
RevenueCat 需要用 IAP Key 来调用 App Store Server API 验证收据。
App Store Connect → 用户和访问 → 密钥 → App 内购买项目 点 + 生成密钥 → 下载 .p8文件(仅下载一次,妥善保存)记下 Key ID 和 Issuer ID
回到 RevenueCat Dashboard → iOS App Settings → In-App Purchase Key Configuration:
上传 .p8文件填入 Key ID 和 Issuer ID
获取 Shared Secret(仅当你需要自己接 Apple 通知时需要):
App Store Connect → 你的 App → 功能 → App 内购买项目 → 订阅状态的 "共享密钥" → 生成。注意 RevenueCat 通过 IAP Key 已经自动完成了收据验证,通常不需要配置 Shared Secret。这个密钥主要在你需要自己接收 App Store Server Notifications 时使用。
4.3 Google Play Console 配置
创建订阅商品:
Google Play Console → 你的 App → 创收 → 订阅 创建订阅 → 填写产品 ID(如 monthly_sub)、标题、说明创建 Base Plan(订阅基准方案): 计费周期:月/季/半年/年 价格 续订类型:自动续订 / 预付费
Android 这边需要注意:一个 Subscription 下可以有多个 Base Plan(比如月度方案和年度方案放在同一个商品里),也可以拆成多个 Subscription。RevenueCat 两种都支持。
创建 Service Account:
RevenueCat 需要用 Service Account 调用 Google Play Developer API 来验证购买。
Google Cloud Console → 选择你的项目(或新建) 启用 Google Play Developer API IAM 与管理 → 服务账号 → 创建服务账号 创建后 → 密钥 → 添加密钥 → JSON → 下载
回到 Google Play Console → 用户和权限 → 邀请新用户:
输入服务账号的邮箱 权限选择 "查看财务数据"(Financial data viewer,只读权限就可以)
回到 RevenueCat Dashboard → Android App Settings → Store Integration:
上传 JSON Key 文件 填入 Package Name
配置完成后,RevenueCat 会自动通过 Google Play Developer API 验证每一笔购买。
05 Paywall:远程配置的订阅购买页面
RevenueCat 的 Paywall 是你整个付费流程里最直接面对用户的那层 UI。本质上它就是你把 Offering 展示给用户的视觉页面——但是厉害的地方在于,这个页面完全在 Dashboard 里远程配置,不需要写代码,更不需要发版。

5.1 什么是 Paywall
每个 Offering 可以绑定一个 Paywall(也可以没有) Paywall 是原生的——iOS 用 SwiftUI 渲染,Android 用 Jetpack Compose 渲染,不是 WebView 你可以在 Dashboard 的 WYSIWYG 编辑器里拖拽设计、改文案、调样式 改完 实时生效,用户下次打开 App 就看到新页面
传统的做法:改一次价格 → 改代码 → 提审 → 等审核 → 用户更新 App → 看到新价格。RevenueCat Paywall 的流程:Dashboard 改个数字 → 保存 → 用户下次打开就看到新价格。没有发版,没有审核。
5.2 Dashboard 配置
在 RevenueCat 左侧菜单进入 Paywalls,可以看到这样的流程:
- 选模板
— RevenueCat 提供多套预设模板(基础款、功能对比款、试用品推广款等),可以直接用或在此基础上改 - 拖拽编辑器
— 图层式编辑,支持修改:商品展示顺序、价格文案、按钮文字、背景色/渐变、图片、字体大小等 - 按条件展示
— 同一个 Offering 可以配多个 Paywall,按用户属性(地区、使用天数、是否订阅过等)展示不同版本 - 预览
— 支持在 Dashboard 里直接预览手机效果,也可以生成链接在真机上预览
5.3 A/B 测试(Experiments)
RevenueCat 的 Experiments 功能是 Paywall 最实用的能力之一:
最多同时跑 4 个变体 每个变体可以绑定不同的 Offering + Paywall(不同的商品组合、不同的设计) 追踪完整转化漏斗:展示 → 点击 → 购买 长期追踪留存数据,看哪个变体的用户 LTV 更高 Dashboard 自动计算统计显著性,告诉你哪个变体胜出
5.4 代码集成
iOS (SwiftUI):
import RevenueCatUI// 方式一:自动判断是否需要展示 PaywallstructContentView:View {var body: someView {ContentView() .presentPaywallIfNeeded( requiredEntitlementIdentifier: "pro_access" ) { customerInfo in// 用户购买成功或已拥有权限,关闭 Paywall } }}// 方式二:手动展示 PaywallViewstructPaywallContainer:View {var body: someView {PaywallView() }}Android (Jetpack Compose):
// 方式一:Paywall DialogPaywallDialog( onDismiss = { /* 关闭回调 */ }, onPurchaseCompleted = { customerInfo ->if (customerInfo.entitlements["pro_access"]?.isActive == true) {// 购买成功 } })// 方式二:嵌入到你的 Composable 中PaywallView( offering = offerings.current, onPurchaseCompleted = { /* ... */ })5.5 注意事项
RevenueCatUI | com.revenuecat.purchases:purchases-ui | |
UIKit 怎么办? RevenueCat 的 Paywall SDK 主要面向 SwiftUI 和 Jetpack Compose。如果你还在用 UIKit 或 View System,可以自己构建 UI,用 RevenueCat SDK 获取 Offering 和 Package 数据,然后走
purchase(package:)手动完成购买流程。功能上完全不受影响,只是 Paywall 的远程配置能力用不了。
06 iOS 接入实战(Swift)
安装 SDK
通过 Swift Package Manager 添加:
https://github.com/RevenueCat/purchases-ios-spm.git选择 RevenueCat 和 RevenueCatUI(用于 Paywall)两个 Product。别忘了在 Target → Capabilities 中开启 In-App Purchase 能力。
初始化
在 App 启动时配置,只需要一次:
import RevenueCat// 通常在 AppDelegate 或 App.init() 中Purchases.logLevel = .debug // 开发时开启Purchases.configure( withAPIKey: "appl_你的_public_api_key", appUserID: nil// nil 会自动生成匿名 ID)appUserID 传 nil 时,SDK 自动生成一个匿名 ID。如果你有自己的用户系统,之后通过 logIn() 关联。
获取商品并发起购买
// 获取当前配置的 Offeringlet offerings =tryawaitPurchases.shared.offerings()guardlet current = offerings.current else { return }let monthly = current.monthly // 直接拿到 Package// 发起购买do {let result =tryawaitPurchases.shared.purchase(package: monthly)if result.customerInfo.entitlements["pro_access"]?.isActive ==true {// 购买成功,解锁功能 }} catchlet error {print("购买失败: \(error)")}SDK 内部帮你完成了:StoreKit 支付 → 收据上传 → 服务端验证 → CustomerInfo 更新 → finishTransaction。
检查订阅状态
let info =tryawaitPurchases.shared.customerInfo()let isPro = info.entitlements["pro_access"]?.isActive ==truelet willRenew = info.entitlements["pro_access"]?.willRenew ==truelet expDate = info.entitlements["pro_access"]?.expirationDate恢复购买
let info =tryawaitPurchases.shared.restorePurchases()苹果要求 App 必须有恢复购买按钮,这一行搞定。
07 Android 接入实战(Kotlin)
添加依赖
// app/build.gradle.ktsdependencies { implementation("com.revenuecat.purchases:purchases:9.x.x") implementation("com.revenuecat.purchases:purchases-ui:9.x.x")}SDK 自带 BillingClient,不需要再加。
初始化
classMyApplication:Application() {overridefunonCreate() {super.onCreate() Purchases.logLevel = LogLevel.DEBUG Purchases.configure( PurchasesConfiguration.Builder(this, "goog_你的_api_key") .appUserID(null) .build() ) }}原本需要手动创建 BillingClient、处理连接重连、注册 PurchasesUpdatedListener、查询已有商品——现在这些都在 configure() 内部自动完成了。
获取商品并发起购买
classPaywallViewModel {// 获取当前 OfferingsuspendfunfetchProducts(): Package? {val offerings = Purchases.sharedInstance.awaitOfferings()return offerings.current?.monthly }// 发起购买suspendfunpurchase(activity: Activity, pkg: Package) {try {val result = Purchases.sharedInstance.awaitPurchase( PurchaseParams.Builder(activity, pkg).build() )if (result.customerInfo.entitlements["pro_access"]?.isActive == true) {// 购买成功 → 解锁功能 } } catch (e: PurchasesTransactionException) {when { e.userCancelled -> { /* 用户取消 */ }else -> { /* 错误处理 */ } } } }}awaitPurchase() 内部:构建 BillingFlowParams → launchBillingFlow → 等待回调 → 上传 token → RevenueCat 服务端验证 → 自动 acknowledgePurchase → 返回结果。可重试的错误自动重试。
检查订阅状态
val info = Purchases.sharedInstance.awaitCustomerInfo()val isPro = info.entitlements["pro_access"]?.isActive监听状态变更
Purchases.sharedInstance.updatedCustomerInfoListener = UpdatedCustomerInfoListener { customerInfo -> updateUI(customerInfo) }08 iOS vs Android 接入对比
Purchases.configure(withAPIKey:) | PurchasesConfiguration.Builder | |
offerings() | awaitOfferings() | |
purchase(package:) | awaitPurchase(PurchaseParams) | |
customerInfo() | awaitCustomerInfo() | |
restorePurchases() | awaitRestore() | |
updatedCustomerInfoListener |
无论 iOS 还是 Android,调用方式几乎一样——这就是 RevenueCat 最大的价值。

09 Dashboard 背后的能力
RevenueCat 真正值钱的不只是 SDK 封装,而是服务端+管理后台那一整套能力:
收据验证,不用自己搭服务器 — 每次购买完成后 RevenueCat 后端自动调 Apple/Google 的 API 验证收据真实性。你不需要维护收据验证服务,不用担心验证逻辑过期。
订阅生命周期自动化 — 续订、过期、宽限期、账单重试、退款——这些状态流转全部由 RevenueCat 管理。你的 App 只需问一句 entitlement.isActive 就知道是否该放行。
Webhook 事件通知 — 任何订阅状态变更(续订、取消、退款、过期等)通过 Webhook 推送到你的服务器,格式统一、跨平台归一。
10 什么时候该用,什么时候不该用
对大多数 App 来说,把内购基础设施交给 RevenueCat,省下的不只是开发时间,更是持续的维护成本。下次产品经理说"加个 A/B 测试"的时候,你就不用再骂人了。
一句话总结:RevenueCat 把 Apple 和 Google 两套内购 API 封装成一套 SDK,收据验证、订阅状态管理、Paywall 配置全包了。省掉一个后端加双平台适配的工作量,对于独立开发者和小团队来说,性价比确实很高。
夜雨聆风