Unified Platform Host
推送通知
APNs Device Token 注册与已鉴权的测试推送端点。
推送能力集成了原生 App 搭建期需要的完整闭环:把设备的 APNs token 绑定到 当前登录用户、通过 APNs HTTP/2 向自己的设备发送真实测试通知(sandbox 或 production),并自动清理失效 token。它是自助验证工具——不是通用的群发/营销 系统。
提供的能力
device_tokens表,把每个 APNs/FCM token 绑定到一个用户。PUT /api/app/v1/device-tokens——幂等 upsert(支持Idempotency-Key)。DELETE /api/app/v1/device-tokens/:token——删除 token(退出登录时)。POST /api/app/v1/notifications/test-push——向当前用户自己的 iOS 设备发送 测试通知。- 基于 Token 的 APNs 鉴权(
.p8密钥,无需证书),支持sandbox与production环境。
重要文件
| 文件 | 作用 |
|---|---|
src/lib/db/schema/app.ts | device_tokens 表 |
src/server/app/devices/deviceTokenService.ts | 带归属规则的 upsert/删除 |
src/server/app/push/apns.ts | APNs HTTP/2 客户端(JWT 鉴权、环境 host) |
src/server/app/push/pushTestService.ts | 测试推送编排 + 失效 token 清理 |
Device Token
Token 标识一台设备安装,因此在表中全局唯一;同一个 token 在另一个登录 用户下重新注册会转移归属(设备换了账户)。归属始终来自 Session——客户端 只能把 token 注册给自己,删除他人的 token 表现为 not-found。
PUT /api/app/v1/device-tokens { "token": "<hex>", "platform": "ios" }
DELETE /api/app/v1/device-tokens/<token>在启动/登录、iOS 下发 token 时注册;退出登录时删除。
APNs 配置
服务端使用基于 Token 的 Provider 密钥签署 APNs 请求(App Store Connect →
Users and Access → Integrations → Keys,创建 APNs Auth Key .p8):
APNS_TEAM_ID=… # Apple Developer 团队 ID
APNS_KEY_ID=… # .p8 密钥的 Key ID
APNS_BUNDLE_ID=com.example.app # 作为 apns-topic 发送
APNS_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n…\n-----END PRIVATE KEY-----"APNS_PRIVATE_KEY 支持 \n 转义,.p8 内容可以放进一行环境变量。这些是
服务端专属机密——只由测试推送端点惰性读取,绝不能到达任何客户端。
测试推送端点
POST /api/app/v1/notifications/test-push
{ "title?": "…", "body?": "…", "deeplink?": "soar:///notifications", "environment?": "sandbox" }- 范围: 只发送给当前 Session 用户的 iOS token,最多 10 台设备。 无法指定其他用户。
- 环境: Xcode Debug 构建用
sandbox,TestFlight/App Store token 用production——token 只在签发它的环境有效。 - Deeplink: 只接受
soar:或https:URL;其他值回退到默认。 - 限流: 每用户每分钟 5 次。
- 响应:
{ environment, sent, failed, deliveries },含每台设备的状态和 token 的最后 8 位用于辨识。
失效 Token 清理
当 APNs 返回 BadDeviceToken 或 Unregistered 时,对应记录会被自动删除——
由重装或环境不匹配产生的过期 token 会在下一次测试推送时消失,而不是不断
堆积。
测试推送返回 DEVICE_TOKEN_NOT_FOUND(404)表示该用户没有已注册的 iOS
token——先注册设备,再发送。
