RevenueCat 是 iOS 上做 IAP 最省事的方案——不用花一周搞收据验证、恢复购买、订阅边界情况。这篇讲什么时候用、什么时候别用、30 分钟接入流程。
问题背景
Apple 的 StoreKit 管支付流程本身,但围绕它的一切——收据验证、服务端订阅状态、恢复购买、跨平台用户身份、数据分析——都要自己搞。RevenueCat 是个托管服务,全包,独立开发者也能用。代价是依赖第三方。2026 年大部分独立 App 来说这笔交易值;高收入 App 最终走原生 StoreKit 更划算。
判断标准
- 在给独立 App 加订阅或非消耗品 IAP。
- 不想自己写收据验证服务器。
- 预期之后会扩展到多平台(iOS + Android + 网页)。
- 收入还在 RevenueCat 免费额度内($2,500/月)——或者能接受抽成。
快速结论
想这周就上 IAP、不想自己搞基础设施,用 RevenueCat。除非有合规要求、收入很高,或者已经有强后端,否则别跳过它。
实操步骤
- 先在 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 里填本地化标题和说明。
-
在 RevenueCat → Project Settings → API Keys 拿 iOS 公开 SDK key。Project Settings → Apple App Store 里填 App Store Connect 的 issuer ID / key ID / 私钥。
-
在 RevenueCat 配 Entitlements 和 Offerings:
Entitlement: "pro" (用户能拿到什么)
↓ 关联到 ↓
Products: pro_monthly、pro_yearly、pro_lifetime
Offering: "default" (paywall 显示什么)
↓ 包含 ↓
Packages: $rc_monthly → pro_monthly
$rc_annual → pro_yearly
$rc_lifetime → pro_lifetime
这层间接关系,让你不发新版也能换产品组合。
- SPM 装 SDK(
https://github.com/RevenueCat/purchases-ios),App 启动初始化:
// AppDelegate.swift 或 App.swift
import RevenueCat
@main
struct MyApp: App {
init() {
Purchases.logLevel = .info
Purchases.configure(withAPIKey: "appl_XXXXXXXXXXXXXXXX")
}
var body: some Scene { WindowGroup { ContentView() } }
}
- 拉 offering、展示 paywall:
import RevenueCat
func loadPaywall() async throws -> Offering? {
let offerings = try await Purchases.shared.offerings()
return offerings.current // 对应 dashboard 里的 "current" offering
}
func purchase(_ package: Package) async throws -> Bool {
let result = try await Purchases.shared.purchase(package: package)
let hasPro = result.customerInfo.entitlements["pro"]?.isActive == true
return hasPro
}
- 按 entitlement 而不是 product ID 判断权限,新增产品就能自动生效:
func userHasPro() async -> Bool {
guard let info = try? await Purchases.shared.customerInfo() else { return false }
return info.entitlements["pro"]?.isActive == true
}
// SwiftUI 用法
if await userHasPro() {
AdvancedFeatureView()
} else {
PaywallView()
}
- 恢复购买——Apple 强制要求(3.1.1)。RevenueCat 一行:
func restore() async throws -> Bool {
let info = try await Purchases.shared.restorePurchases()
return info.entitlements["pro"]?.isActive == true
}
- 后端校验——监听 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');
}
- 提审前沙盒测一遍:
App Store Connect → Users and Access → Sandbox → Testers → +
• 新建 test@example.com(不要用你自己的 Apple ID)
• Region 选 United States
设备 → 设置 → App Store → 沙盒账号 → 登录
TestFlight → 安装 build → 每个 package 都买一次 → 换台干净设备点 Restore
RevenueCat dashboard → Activity 里几秒内就能看到沙盒交易——Apple 自己的报表滞后好几个小时。
容易踩的坑
- 把 product ID 硬编码进 App。用 Offerings 这样改产品不用发新版。
- 没加”恢复购买”按钮。Apple 3.1.1 条款要求非消耗品和订阅必须有。
- 没处理 “pending purchase” 状态(家长审批、支付问题)。用沙盒家长控制测。
- 后端只信客户端 entitlement 检查。任何高价值访问都要通过 webhook 在服务端校验订阅状态。
- 没在 App Store Connect 加沙盒测试账号。用真 Apple ID 会真扣钱。
- 以为免费额度是无限的。超过 $2,500/月就抽成,定价时要算进去。
这篇适合谁
想避免后端工作、做第一或第二款带 IAP 的 App 的独立开发者和小团队。
这篇不适合谁
有严格”不接第三方数据”政策的 App、收入很高抽成累的、已经有成熟订阅基础设施的。
FAQ
- RevenueCat 收多少: 每月跟踪收入 $2,500 以内免费;超过抽 1%。和省下的工程时间比一下。
- 能在 TestFlight 用吗: 能。TestFlight build 走 StoreKit 沙盒,RevenueCat SDK 正确处理沙盒交易。
- Android 怎么办: RevenueCat 同一个 SDK 也支持 Google Play,API 统一,跨平台用户身份很简单。
- 以后能换掉 RevenueCat 吗: 能但不简单。可以导出交易数据重做原生 StoreKit,但要预留几天工作量。