Soar API Setup
将 Expo iOS 与 Android 连接到兼容 Unified Platform 宿主:环境键、宿主环境、Session 与验证。
本页是 Unified Mode 版的 Supabase Setup: 让原生 App 对着一个兼容 Web 宿主(而不是 Supabase 项目)运行所需的全部配置。 还没确定模式的话,先看后端模式——注意 Expo Web 只支持 Standalone;Unified 产品里浏览器由 Web 宿主负责。
不按框架名称给予宿主特权——Next.js、Nuxt、TanStack Start 都可以;是否符合 冻结契约才是兼容边界。
1. 部署兼容宿主
把任意一个 Web 模板部署为 Unified Platform Host,并完成其宿主侧配置 (数据库、Better Auth URL 与密钥、App API):
先在 Web 端注册并确认 /api/auth/get-session 正常,再动 Expo 侧。跨模板的
整体流程见平台 Unified 快速开始。
2. 配置客户端构建
Unified Mode 需要两个环境键(按构建 Profile 设置——模式独立于
APP_VARIANT,development/preview/production 构建可以各自指向自己的部署):
# .env / EAS 构建 Profile
EXPO_PUBLIC_SOAR_BACKEND_MODE=soarApi
# 部署 Origin,不要带 /api/app/v1——App 会自行拼接 API 路径。
EXPO_PUBLIC_SOAR_API_BASE_URL=https://your-web-app.example.com
# 可选:Unified 构建在浏览器中被打开时展示的产品链接。
EXPO_PUBLIC_UNIFIED_WEB_APP_URL=https://your-web-app.example.comEXPO_PUBLIC_SUPABASE_* 键可以留空——这个模式下永远不会构建 Supabase 客户
端。请求 Origin 由各 variant 的 App scheme 派生:生产为
soar-starter-expo://,开发/预览构建为 soar-starter-expo-dev:// /
soar-starter-expo-preview://。
配置错误会终止当前构建。EXPO_PUBLIC_SOAR_API_BASE_URL 缺失或格式不对会
抛出 BackendConfigurationError;在 Expo Web 打开 Unified 构建会抛出
UnifiedWebUnsupportedError——不存在静默 Supabase 回退。
3. 为这个 App 配置宿主
服务端(所选宿主的部署环境)需要 原生认证 所描述的原生支持:
| 服务端变量 | Expo App 为什么需要它 |
|---|---|
APP_SCHEME | 必须与当前 variant 的 scheme 一致(如 soar-starter-expo://,开发期用 -dev/-preview 变体);Better Auth 会用 403 拒绝不受信任的 Origin。 |
APPLE_APP_BUNDLE_IDENTIFIER | iOS 原生 Apple ID Token 登录的 audience(含 variant 后缀的 Bundle ID)。 |
GOOGLE_IOS_CLIENT_ID / GOOGLE_ANDROID_CLIENT_ID | 原生 Google ID Token 登录的 audience 白名单条目。 |
REVENUECAT_WEBHOOK_AUTHORIZATION + REVENUECAT_PRODUCT_* | 把 App Store / Google Play 购买同步到共享的订阅行。 |
APNS_* | iOS 测试推送端点的服务端 APNs 凭据。 |
STORAGE_PROVIDER(生产另加 R2_*) | 支撑上传服务的 presigned 直传对象存储。 |
4. Session 存在 SecureStore 里
Unified Mode 下 App 使用 Better Auth 的 Bearer token(set-auth-token
响应 header)认证,而不是 Cookie:
- Token 只持久化在
expo-secure-store(ExpoSecureSessionStore)—— 绝不进 AsyncStorage、绝不进 Query cache、绝不进日志。 - 存储键按构建 variant 和 API Base URL 命名空间隔离,开发或预览 Token 绝不 会被生产构建恢复。
- 重启后恢复会话并向服务端校验;退出登录会同时清理存储的 Token 和内存状态。
- Session 存于数据库、可撤销:在 Web 端撤销会话会让移动端 Token 立即失效,
App 把
401视为「需要重新登录」——不会无限重试,也不会回退到 Supabase 认证。
5. RevenueCat appUserID
购买层始终用当前用户 ID 登录 RevenueCat——Unified Mode 下即 Better Auth 用户
ID。正是它让服务端的 RevenueCat Webhook
能把 app_user_id 解析回同一个 Better Auth 用户,并更新 Web 端也在读取的
同一行共享订阅。
保持 RevenueCat 的 Restore Behavior 为禁用 Transfer:收据已绑定其他账户 时应当出现面向支持的明确错误,而不是在用户之间悄悄转移权益。
6. 推送通知
Unified 构建按平台注册设备 Token:iOS 用 APNs,Android 用 FCM。冻结的 v1 测试推送端点仅支持 APNs,因此测试发送在 iOS 可用、在 Android 显示为「不支 持」——真实的 FCM 送达不受影响。
验证配置
在两端跑一遍共享冒烟测试:
- 在 iOS/Android 注册或登录(邮箱、iOS 上的 Apple、原生 Google),然后在 Web 端打开同一个账户。
- 在一端更新 Profile,从另一端读取。
- 跨两端创建、编辑、排序、删除 Todo。
- 上传头像并确认其完成 URL 可读。
- 从 Web 端撤销移动端会话,确认 App 回到登录页。
- 沙盒购买后,确认两端出现同一份权益。
- 在每个平台注册设备 Token;在 iOS 触发 APNs 测试推送。
- 在 Expo Web 打开 Unified 构建,确认展示 Web 应用提示而不是进入登录。
想要一组具体宿主+客户端的端到端流程,跟 Next.js + Swift Unified Setup 走—— 步骤与 Expo 一一对应。
