RevenueCat 是 iOS 上做内购最快的方案,不用花一周去搞收据验证、恢复购买和一堆订阅边界情况。截至 2026 年 6 月,它每月跟踪收入(MTR)$2,500 以内免费,超出部分抽 1%。本文给你 30 分钟接入路径、SwiftUI 代码,以及一个诚实的判断:什么时候裸用 StoreKit 2 反而更划算。
一句话结论
- 它是什么: Apple StoreKit 之上的一层托管服务,替你扛收据验证、订阅状态、跨平台身份,还自带一套服务端驱动的付费墙。
- 价格(2026 年 6 月): 每月跟踪收入 $2,500 以内免费,超出抽 1%(按未扣 Apple 抽成的总收入算)。企业版另议价。(见官方价格页)
- SDK:
purchases-ios5.x(截至 2026 年 6 月 3 日为 5.76.0),在 iOS 16+ 上默认走 StoreKit 2。付费墙在RevenueCatUI这个包里。 - 该用: 想这周就上内购、又不想自己维护一套验证后端。别用: 只有一个 App、只卖简单非消耗品,而且已经有成熟的服务端工程能力。
RevenueCat vs 裸 StoreKit 2
StoreKit 2 是 Apple 的原生框架,负责支付交易本身,现在也通过签名的 Transaction 对象在设备端做收据校验。但围绕它的一切——跨设备的持久订阅状态、跨平台身份、数据分析、免发版的付费墙——还是得你自己写。RevenueCat 把这层托管了。
| RevenueCat | 裸 StoreKit 2 | |
|---|---|---|
| 收据 / 交易验证 | 服务端托管 | 设备端 Transaction.verify;要给别处用就得自建服务器 |
| 跨设备 / 跨端订阅状态 | 内置(CustomerInfo) | 自己写 |
| 跨平台(iOS + Android + 网页) | 一套 SDK、一个用户身份 | 每个平台分别做 |
| 付费墙 UI | 服务端驱动(RevenueCatUI),免发版 | 手写 SwiftUI |
| Webhook(续费 / 取消 / 退款) | 内置 | Apple App Store Server Notifications V2,自己解析 |
| 成本 | $2,500 MTR 以内免费,超出 1% | $0(只花你自己搭基建的时间) |
| 锁定 | 迁移要几天 | 无 |
对 2026 年大多数独立和小团队 App 来说,这 1% 换回的是好几天的订阅管线工作,值。但当收入高到 1% 的总抽成超过自建基建成本,或者公司政策不允许把购买数据交给第三方时,账就反过来了。
30 秒做决定
下面大部分成立,就用 RevenueCat:
- 你在给独立 App 加自动续订订阅或非消耗品。
- 不想自己跑一台收据验证服务器。
- 预期之后会扩展到多平台(iOS + Android + 网页)。
- 跟踪收入还在 $2,500/月以内,或者能接受超出后抽 1%。
有以下情况就别用:有严格的”不外传购买数据”政策、收入很高 1% 的总抽成不是小数、或者已经有成熟的订阅后端。
接入步骤
1. 先在 App Store Connect 建产品
product ID 是永久的,建好不能改名,所以挑一套以后不会后悔的命名:
pro_monthly 自动续订订阅 $4.99/月
pro_yearly 自动续订订阅 $39.99/年
pro_lifetime 非消耗品 $79.99
每个都要在 App Store Connect → My Apps → Features → In-App Purchases(或 Subscriptions)里填本地化的展示名和说明。新建的订阅在你补全这些信息、附上一张审核截图之前,会一直停在 “Missing Metadata” 状态。
2. 把 App Store Connect 连到 RevenueCat
在 RevenueCat → Project Settings → API Keys 里拿 iOS 的公开 SDK key(以 appl_ 开头)。再到 Project Settings → Apple App Store,把 App Store Connect API 的 Issuer ID、Key ID 和 .p8 私钥填进去,这样 RevenueCat 才能读你的产品、收到服务端通知。
3. 配置 Entitlements 和 Offerings
这层间接关系,就是让你免发版也能改价、改打包组合的关键:
Entitlement: "pro" (用户解锁了什么权限)
关联到
Products: pro_monthly、pro_yearly、pro_lifetime
Offering: "default" (付费墙展示什么)
包含
Packages: $rc_monthly -> pro_monthly
$rc_annual -> pro_yearly
$rc_lifetime -> pro_lifetime
权限判断永远按 entitlement(pro)来,绝不按 product ID。以后加个新价格档,逻辑不用动就能生效。
4. 用 SPM 装两个 SDK 包
添加 https://github.com/RevenueCat/purchases-ios,勾选两个 product:RevenueCat(核心)和 RevenueCatUI(付费墙)。启动时初始化一次:
// App.swift
import RevenueCat
@main
struct MyApp: App {
init() {
Purchases.logLevel = .info
Purchases.configure(withAPIKey: "appl_XXXXXXXXXXXXXXXX")
}
var body: some Scene { WindowGroup { ContentView() } }
}
SDK 5.x 在 iOS 16+ 上默认走 StoreKit 2,所以你免配置就拿到了 Apple 的签名交易校验和 async/await。
5. 展示付费墙(用 RevenueCatUI,别手写)
最快的路子是 presentPaywallIfNeeded 修饰符:它会拉取 current offering、渲染你在 dashboard 里设计好的付费墙,并且只在用户没有该权限时才弹出:
import SwiftUI
import RevenueCatUI
struct RootView: View {
var body: some View {
ContentView()
.presentPaywallIfNeeded(
requiredEntitlementIdentifier: "pro",
purchaseCompleted: { _ in /* 已解锁 */ },
restoreCompleted: { _ in /* 权限激活后自动关闭 */ }
)
}
}
想要一个手动触发的”升级 Pro”按钮?用 sheet 弹出 PaywallView():
.sheet(isPresented: $showPaywall) { PaywallView() }
因为付费墙是服务端驱动的,你能直接在 dashboard 里 A/B 测试布局和文案,不用重新提审。
6. 按 entitlement 判断权限
func userHasPro() async -> Bool {
guard let info = try? await Purchases.shared.customerInfo() else { return false }
return info.entitlements["pro"]?.isActive == true
}
7. 恢复购买(审核指南 3.1.1 强制要求)
任何卖非消耗品或订阅的 App 都必须提供”恢复购买”按钮,否则会被拒。RevenueCat 一行搞定:
func restore() async throws -> Bool {
let info = try await Purchases.shared.restorePurchases()
return info.entitlements["pro"]?.isActive == true
}
8. 用 webhook 在服务端校验
如果你有后端来发放权限,就别只信客户端。监听 RevenueCat webhook,让取消、续费、退款都能传到你的服务器:
// Vercel / Cloudflare Worker —— 最小 webhook 接收器
export async function POST(req: Request) {
const sig = req.headers.get('Authorization');
if (sig !== `Bearer ${process.env.RC_WEBHOOK_SECRET}`) {
return new Response('unauthorized', { status: 401 });
}
const event = await req.json();
// INITIAL_PURCHASE | RENEWAL | CANCELLATION | EXPIRATION | BILLING_ISSUE | ...
await updateUserEntitlement(event.event.app_user_id, event.event.type);
return new Response('ok');
}
9. 提审前先过一遍沙盒
App Store Connect → Users and Access → Sandbox → Test Accounts → +
• 新建 test@example.com(用新邮箱,别用你自己的 Apple ID)
• Region 选 United States
设备 → 设置 → 开发者 → 沙盒 Apple 账号 → 登录
TestFlight → 安装 build → 每个 package 都买一次 → 换台干净设备点 Restore
RevenueCat dashboard → Customer history 里几秒内就能看到沙盒交易;Apple 自己的销售报表要滞后几个小时。
别栽在这几个坑上
- 把 product ID 硬编码进 App。 用 Offerings,这样改价、改打包都不用发版。
- 没加”恢复购买”按钮。 3.1.1 直接拒。接好
restorePurchases()。 - 没处理 “pending purchase” 状态(Ask to Buy 家长审批、支付重试)。用沙盒的 Ask to Buy 测一遍。
- 后端也做权限校验,却只信客户端。 任何高价值访问都要靠 webhook 在服务端确认状态。
- 真卡被扣钱。 务必先建沙盒测试账号,用真 Apple 账号是真买真扣。
- 以为免费额度无上限。 超过 $2,500/月跟踪收入就抽 1%,定价时要算进去。
- 忘了 Apple 自己那一刀。 RevenueCat 的 1% 是叠在 Apple 抽成之上的,不是替代它(见 FAQ)。
FAQ
- RevenueCat 收多少钱? 每月跟踪收入 $2,500 以内免费,超出抽 1%,按未扣 Apple 抽成的总收入计算,所以它叠在 Apple 的 15% 或 30% 之上,不在里头。企业版另议价。
- Apple 自己抽多少? 标准 30%,但 App Store 小企业计划(Small Business Program)把它降到 15%,适用于年度净收入低于 $100 万的开发者(大多数独立开发者都符合);标准自动续订订阅在订阅者付费满一年后也会降到 15%。
- 能在 TestFlight 用吗? 能。TestFlight build 走 StoreKit 沙盒,SDK 能正确处理沙盒交易,不会真扣钱。
- 还需要懂 StoreKit 吗? 要懂一点。SDK 5.x 底层用 StoreKit 2,但产品、价格、税务还是你自己在 App Store Connect 里配,RevenueCat 不替你做这块。
- Android 怎么办? 同一套 SDK 和统一 API 覆盖 Google Play。用一个
app_user_id就能把用户在 iOS、Android、网页之间打通。 - 以后能换掉 RevenueCat 吗? 能,但要预留几天。可以导出交易记录,重做到裸 StoreKit 2 / Google Play Billing,再重新校验权限。