Apple开发_整合 Sign in with Apple (SIWA) 的订阅系统完整流程和可视化图表
🔑 关键流程原则
- 先登录后订阅:强制用户先通过Apple ID登录
- 绑定订阅到Apple ID:而非设备
- 自动恢复:同一Apple ID跨设备自动同步订阅状态
📱 用户操作流程图
sequenceDiagram
participant 用户
participant App
participant Apple服务器
participant 你的服务器
用户->>App: 点击「订阅会员」
App->>用户: 弹出Sign in with Apple授权页
用户->>Apple服务器: 选择Apple ID登录(可选隐藏邮箱)
Apple服务器-->>App: 返回用户唯一标识(identityToken)
App->>你的服务器: 上报identityToken+设备信息
你的服务器->>Apple服务器: 验证identityToken有效性
Apple服务器-->>你的服务器: 返回验证结果(包含userIdentifier)
你的服务器->>数据库: 绑定userIdentifier到订阅计划
你的服务器-->>App: 返回订阅成功
App->>用户: 解锁会员功能
loop 跨设备同步
用户->>新设备: 使用同一Apple ID登录
新设备->>你的服务器: 请求订阅状态(userIdentifier)
你的服务器-->>新设备: 返回有效订阅
新设备->>用户: 自动恢复会员
end
🛠 分步技术实现
1. 用户登录阶段
// 1. 集成Sign in with Apple按钮
import AuthenticationServices
let button = ASAuthorizationAppleIDButton()
button.addTarget(self, action: #selector(handleAppleID), for: .touchUpInside)
// 2. 处理登录回调
@objc func handleAppleID() {
let request = ASAuthorizationAppleIDProvider().createRequest()
request.requestedScopes = [.email] // 可选获取邮箱
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.performRequests()
}
// 3. 获取用户唯一标识
func authorizationController(controller: ASAuthorizationController,
didCompleteWithAuthorization authorization: ASAauthorization) {
guard let credential = authorization.credential as? ASAuthorizationAppleIDCredential,
let identityToken = credential.identityToken else { return }
let userIdentifier = credential.user // 永久唯一标识
sendToServer(identityToken: String(data: identityToken, encoding: .utf8)!)
}
2. 服务器验证逻辑
# 验证Apple身份令牌(Python示例)
def verify_apple_token(identity_token):
import jwt
from apple.auth import verify_apple_id_token
# 1. 验证签名(需苹果公钥)
claims = verify_apple_id_token(identity_token, audience="com.your.bundleid")
# 2. 提取关键信息
return {
"user_id": claims["sub"], # 唯一不变标识
"email": claims.get("email", ""),
"is_private_email": claims.get("email_verified", False)
}
3. 订阅绑定与恢复
// 订阅购买成功时绑定
func paymentQueue(_ queue: SKPaymentQueue,
updatedTransactions transactions: [SKPaymentTransaction]) {
for tx in transactions {
if tx.transactionState == .purchased {
let receipt = getReceiptData()
server.linkSubscription(
userId: currentAppleUserId,
receipt: receipt
)
}
}
}
// 检查订阅状态
func checkSubscription() {
server.getSubscriptionStatus(userId: currentAppleUserId) { isValid in
DispatchQueue.main.async {
self.isPremium = isValid
}
}
}
📌 必须实现的细节
-
双重验证
- 每次启动App时检查
ASAuthorizationAppleIDProvider().getCredentialState
func checkAppleIDStatus() { ASAuthorizationAppleIDProvider().getCredentialState(forUserID: userId) { state, error in if state == .revoked { // 用户已取消Apple ID授权 server.revokeSubscription(userId: userId) } } } - 每次启动App时检查
-
隐私合规提示
在Info.plist中添加:<key>ASAuthorizationAppleIDProvider</key> <string>用于恢复您的会员权益</string> -
跨设备同步流程图解
graph LR A[设备A登录] -->|userIdentifier:123| B[你的服务器] B --> C[(数据库记录)] D[设备B登录] -->|同userIdentifier:123| B B -->|查询记录| C --> E[自动恢复订阅]
⚖️ 法律与审核要求
- 必须允许用户:
- 随时在iOS设置中取消Apple ID授权
- 通过Apple ID恢复已购订阅
- 禁止行为:
- 要求额外注册密码账户
- 限制同一Apple ID的设备数量(除非明确告知)
💡 体验优化建议
-
智能恢复提示
func showRestoreTip() { if isFirstLaunch && !hasLocalSubscription { let alert = UIAlertController( title: "检测到Apple ID历史订阅", message: "要恢复之前的会员权益吗?", preferredStyle: .alert ) alert.addAction(UIAlertAction(title: "恢复", style: .default) { _ in self.restorePurchase() }) present(alert, animated: true) } } -
多设备管理后台
提供web页面让用户查看所有登录设备:
https://yourdomain.com/apple-devices?user_id=123
这种方案既符合苹果要求,又能实现90%+的跨设备恢复率,且开发成本可控。

浙公网安备 33010602011771号