RevenueCat 内购
配置 iOS 和 Android 订阅、内购与 Webhook
接入 RevenueCat 内购
EasyStarter 移动端使用 RevenueCat 管理 iOS 和 Android 的订阅与内购。RevenueCat 负责与 App Store / Google Play 对接,并通过 Webhook 将订阅状态同步到服务端。
前置准备
在开始之前,请确保以下账号和配置已就绪:
- RevenueCat 账号(免费开始)
- iOS:Apple Developer 账号,App Store Connect 中已创建 App 内购买项目
- Android:Google Play Console 账号,已创建订阅产品
前置:在商店后台创建产品
在配置 RevenueCat 之前,需要先在 App Store Connect 和 Google Play Console 中创建订阅和内购产品,并记录每个产品的 产品 ID。
详细步骤请参阅 创建内购产品 章节。
在 RevenueCat 后台配置
注册并登录 RevenueCat 后,按以下步骤完成后台配置。
1. 创建 App
进入 Project Settings → Apps 页面,点击 New app configuration,选择平台(iOS 选 App Store,Android 选 Google Play)。
- iOS:填写 App 名称和 Bundle ID,然后按照官方文档完成以下两项凭据配置:
- Android:填写 App 名称和 Package Name,按照官方文档配置 Google Play service credentials。
配置完成后点击 Save changes。
2. 导入 Products
Products 是 RevenueCat 对 App Store / Google Play 中具体商品的映射。
进入 Product catalog → Products,点击右上角 Import 按钮。RevenueCat 会自动拉取您在商店后台已创建的产品列表,勾选所有需要的产品(包括月度订阅、年度订阅、终身买断等),点击 Import 完成导入。
如果 Import 后列表为空,说明商店凭据尚未生效或产品尚未在商店后台审核通过。iOS 产品需要先创建好 In-app purchase 并处于"Ready to Submit"及以上状态才能被拉取到。
导入完成后,每个 Product 会显示其 Product Identifier(即 App Store / Google Play 中的产品 ID)。请记录这些 ID,后续在 app-config.ts 中会用到。
3. 配置 Offerings
Offerings 定义了向用户展示的购买方案组合,每个 Offering 下可包含多个 Package(对应不同时长或类型的产品)。
- 进入 Product catalog → Offerings,RevenueCat 默认会有一个名为 default 的 Offering。
- 点击 default 进入详情页,点击 Add Package,依次添加以下三个 Package:
- Monthly:Package Type 选
Monthly,关联对应的月度订阅 Product - Yearly:Package Type 选
Annual,关联对应的年度订阅 Product - Lifetime:Package Type 选
Lifetime,关联对应的终身买断 Product
- Monthly:Package Type 选
- 每个 Package 添加后,在右侧面板中选择对应的 Product(iOS 和 Android 分别选择),然后点击 Save。
Offerings 决定了 App 内显示哪些购买方案。您可以创建多个 Offering 用于 A/B 测试,但 SDK 默认使用 default Offering。
4. 配置 Entitlements
Entitlements 定义了用户购买后获得的权益(即解锁哪些功能)。通常一个 App 只需要一个 Entitlement,例如 pro。
- 进入 Product catalog → Entitlements,点击右上角 New 按钮,填写 Identifier(例如
pro),点击 Save 创建。 - 进入该 Entitlement 的详情页,点击 Attach,在弹出的产品列表中勾选所有需要授予此权益的 Products(Monthly、Yearly、Lifetime 三个都勾选),点击 Attach 保存。
Entitlement Identifier 需要与 eas.json 中的 EXPO_PUBLIC_REVENUECAT_ENTITLEMENT_ID 保持一致。如果您使用 pro,则环境变量也填 pro。
Entitlement 配置完成后,当用户购买任意一个已关联的 Product 时,RevenueCat 会自动将该 Entitlement 标记为 active,App 端通过 SDK 即可判断用户是否有权限。
5. 配置付费墙(可选)
RevenueCat 内置了可视化付费墙编辑器,支持无需发版即可远程修改内购页面。
进入 Paywalls 页面,点击 New paywall,从内置模板中选择一个样式开始编辑:
- 选择要绑定的 Offering(选
default) - 填写付费墙名称
- 配置隐私协议和服务条款的 URL
根据 App Store 审核指南,内购页面必须包含隐私协议和服务条款的链接,否则可能被拒审。
如果所选模板没有 Lifetime Package 的位置,可以复制一个现有 Package 区块,将其类型改为 Lifetime,并修改对应的展示文案。编辑完成后点击 Publish 发布,付费墙即可在 App 中生效。
更多付费墙变量和自定义选项参考 RevenueCat 官方文档。
6. 获取 API Key 和 Entitlement ID
获取 SDK API Key:进入 Project Settings → API Keys,找到对应平台的 Public SDK key(iOS 以 appl_ 开头,Android 以 goog_ 开头),点击 Show Key → Copy,分别填入 eas.json 的 EXPO_PUBLIC_REVENUECAT_IOS_API_KEY 和 EXPO_PUBLIC_REVENUECAT_ANDROID_API_KEY。
获取 Secret API Key:在同一页面找到 Secret keys,复制后填入服务端环境变量 REVENUECAT_SECRET_API_KEY(用于服务端查询订阅状态)。
获取 Entitlement ID:进入 Product catalog → Entitlements,复制您创建的 Entitlement 的 Identifier,填入 eas.json 的 EXPO_PUBLIC_REVENUECAT_ENTITLEMENT_ID。
7. 配置 Webhook(同步订阅状态到服务端)
RevenueCat 通过 Webhook 将订阅事件(购买、续费、取消等)实时推送到 Server。EasyStarter 的服务端已内置处理逻辑,只需配置好 Webhook URL 即可。
开发环境(ngrok)
本地开发时 Server 运行在 localhost,RevenueCat 无法直接访问。需要使用 ngrok 将本地端口暴露到公网。
-
安装 ngrok(如果尚未安装):
brew install ngrok -
启动本地 Server:
pnpm dev:server默认监听
http://localhost:3001。 -
开启 ngrok 隧道:
ngrok http 3001ngrok 会输出一个公网 URL,例如:
Forwarding https://a1b2-123-456-789.ngrok-free.app -> http://localhost:3001 -
在 RevenueCat Dashboard → Project Settings → Integrations → Webhooks → Add webhook,Webhook URL 填写:
https://a1b2-123-456-789.ngrok-free.app/api/webhooks/revenuecat -
在 Authorization header 字段中填入你自己生成的随机密钥。推荐使用完整的 Bearer Token 格式:
# 先生成一个随机值 openssl rand -hex 32将生成的值拼上
Bearer前缀,例如Bearer a1b2c3d4...,填入 RevenueCat Webhook 配置的 Authorization header 字段。然后把同一个完整值填入
apps/server/.dev.vars:apps/server/.dev.vars REVENUECAT_WEBHOOK_SECRET=Bearer your_random_secret
REVENUECAT_WEBHOOK_SECRET 是你自己生成并配置的值,而不是 RevenueCat 颁发的密钥。RevenueCat 每次调用 Webhook 时会将这个值作为 Authorization 请求头原样带过来,服务端再做比对验证。建议直接写完整的 Bearer xxx 形式,最清晰且不易配错。
ngrok 免费版每次重启隧道 URL 会变化,需要同步更新 RevenueCat 后台的 Webhook URL。如果频繁调试,可以注册 ngrok 账号使用固定域名。
生产环境
部署到 Cloudflare Workers 后,Server 拥有固定的公网地址,直接配置即可。
-
在 RevenueCat Dashboard → Project Settings → Integrations → Webhooks → Add webhook,Webhook URL 填写:
https://your-server.workers.dev/api/webhooks/revenuecat -
在 Authorization header 字段中填入你自己生成的随机密钥(与开发环境使用相同的格式):
openssl rand -hex 32将生成值拼上
Bearer前缀,例如Bearer a1b2c3d4...,填入 RevenueCat Webhook 配置的 Authorization header 字段,同时将同一个完整值填入apps/server/.env.production(或通过wrangler secret管理):apps/server/.env.production REVENUECAT_WEBHOOK_SECRET=Bearer your_random_secret -
推送 Secret 到 Cloudflare:
pnpm -F server secrets:bulk:production
更新 eas.json 环境变量
将获取的 API Keys 和 Entitlement ID 填入 apps/native/eas.json 中各 profile 的 env 块:
{
"build": {
"development": {
"env": {
"EXPO_PUBLIC_SERVER_API_URL": "https://your-server.workers.dev",
"EXPO_PUBLIC_WEB_APP_URL": "https://your-app.com",
"EXPO_PUBLIC_REVENUECAT_IOS_API_KEY": "appl_xxxxxxxxxxxxxxxx",
"EXPO_PUBLIC_REVENUECAT_ANDROID_API_KEY": "goog_xxxxxxxxxxxxxxxx",
"EXPO_PUBLIC_REVENUECAT_ENTITLEMENT_ID": "pro"
}
},
"preview": {
"env": {
// ... 同上,可使用相同或独立的 RevenueCat 项目
}
},
"production": {
"env": {
"EXPO_PUBLIC_SERVER_API_URL": "https://your-server.workers.dev",
"EXPO_PUBLIC_WEB_APP_URL": "https://your-app.com",
"EXPO_PUBLIC_REVENUECAT_IOS_API_KEY": "appl_xxxxxxxxxxxxxxxx",
"EXPO_PUBLIC_REVENUECAT_ANDROID_API_KEY": "goog_xxxxxxxxxxxxxxxx",
"EXPO_PUBLIC_REVENUECAT_ENTITLEMENT_ID": "pro"
}
}
}
}
EXPO_PUBLIC_前缀的变量会被 Expo 注入到客户端代码中,不要将私密信息放在这里。RevenueCat SDK Key 是公开的客户端凭据,放在此处是安全的。
更新 app-config.ts 定价配置
packages/app-config/src/app-config.ts 中的 native.payments 定义了 App 内的定价方案,需要与 RevenueCat 后台和 App Store / Google Play 的产品 ID 保持一致:
native: {
payments: {
enabled: true,
provider: "revenuecat",
ios: {
plans: [
{
id: "pro",
prices: [
{
id: "monthly",
provider: "revenuecat",
providerPriceId: "easystarternative_10_1m", // App Store Connect 中的产品 ID
currency: "usd",
amountCents: 1000,
priceType: "subscription",
interval: "month",
status: "active",
},
{
id: "yearly",
provider: "revenuecat",
providerPriceId: "easystarternative_100_1y",
currency: "usd",
amountCents: 10000,
priceType: "subscription",
interval: "year",
status: "active",
},
],
},
{
id: "lifetime",
prices: [
{
id: "lifetime",
provider: "revenuecat",
providerPriceId: "easystarternative_299_lifetime",
currency: "usd",
amountCents: 29900,
priceType: "lifetime",
status: "active",
},
],
},
],
},
android: {
plans: [
{
id: "pro",
prices: [
{
id: "monthly",
provider: "revenuecat",
providerPriceId: "pro_monthly_android", // Google Play Console 中的产品 ID
currency: "usd",
amountCents: 800,
priceType: "subscription",
interval: "month",
status: "active",
},
],
},
],
},
},
},| 字段 | 说明 |
|---|---|
providerPriceId | 对应 App Store Connect / Google Play Console 中的产品 ID,必须完全一致 |
amountCents | 用于 App 内展示价格,单位为分($10.00 = 1000) |
priceType | subscription(订阅)或 lifetime(一次性购买) |
status | active 为上线,inactive 为下架 |
Server 端变量
除了客户端配置,Server 也需要两个 RevenueCat 变量才能处理 Webhook 和服务端 API 调用:
REVENUECAT_SECRET_API_KEY= # RevenueCat Secret API Key(用于服务端查询订阅状态)REVENUECAT_SECRET_API_KEY 在 RevenueCat Dashboard → 项目 → API Keys → Secret keys 中获取。