System & Services 进阶 20m
增强你的 Sign in with Apple 体验
Enhance your Sign in with Apple experience
2022年6月6日
一句话判断
iOS 16 让你的 App 启动时就能自动展示已有登录凭据——密码、Sign in with Apple、Passkey 全部一次搞定,彻底告别”选错登录方式创建重复账号”的噩梦。
这场 Session 讲了什么
Sign in with Apple 的核心问题之一是账号重复:用户可能先用邮箱密码注册,后来又用 Sign in with Apple 创建了第二个账号。Session 的前半部分专门解决这个痛点。
iOS 16 新增了 preferImmediatelyAvailableCredentials 选项。在 App 启动时,你可以同时查询密码凭据和 Sign in with Apple 凭据。如果用户有现成的登录方式,系统直接展示选择界面——用户选对了就不会创建重复账号。
Session 的后半部分深入讲解了 Apple ID Credential 的每个字段含义和使用场景。User ID 是跨 App Team 的稳定标识符。fullName 和 email 只在首次创建账号时返回,后续登录不会再提供——你必须安全缓存这些值。realUserStatus 是基于设备端机器学习的反欺诈指标。
值得深挖的点
- 启动时凭据发现:在
ASAuthorizationController中同时包含ASAuthorizationAppleIDProvider和ASAuthorizationPasswordProvider,调用performRequests(with: .preferImmediatelyAvailableCredentials)。如果没有现成凭据,API 不会强制展示 Sign in with Apple 界面——返回错误让你走标准登录流程。 - Credential 变化监听:用户可能撤销 Sign in with Apple 授权、删除账号或切换 Apple ID。通过
ASAuthorizationAppleIDProvider.credentialState(forUserID:)定期检查授权状态。 - realUserStatus 的三档策略:“likelyReal” 跳过额外验证(不显示 CAPTCHA),“unknown” 当作有限信息的新账号处理(不要封堵),“unsupported” 说明系统无法判断。
- 账号删除处理:如果你的 App 支持账号删除,必须通过 Sign in with Apple REST API 通知 Apple 撤销用户的 Token。
代码片段
import AuthenticationServices
// App 启动时自动发现已有凭据
func discoverExistingCredentials() {
let appleIDProvider = ASAuthorizationAppleIDProvider()
let passwordProvider = ASAuthorizationPasswordProvider()
let controller = ASAuthorizationController(
authorizationProviders: [appleIDProvider, passwordProvider]
)
controller.delegate = self
controller.presentationContextProvider = self
// iOS 16 新选项:只请求立即可用的凭据
controller.performRequests(
options: .preferImmediatelyAvailableCredentials
)
}
func authorizationController(
controller: ASAuthorizationController,
didCompleteWithAuthorization authorization: ASAuthorization
) {
switch authorization.credential {
case let appleIDCredential as ASAuthorizationAppleIDCredential:
// 用户选择了 Sign in with Apple
let userID = appleIDCredential.user
let fullName = appleIDCredential.fullName
let email = appleIDCredential.email
case let passwordCredential as ASPasswordCredential:
// 用户选择了密码登录
let username = passwordCredential.user
let password = passwordCredential.password
default:
break
}
}
func authorizationController(
controller: ASAuthorizationController,
didCompleteWithError error: Error
) {
// 没有现成凭据 → 展示标准登录界面
showStandardLoginFlow()
}
最佳实践
- 在 App 启动时调用凭据发现,让用户一键登录
- 首次获取的 fullName 和 email 必须安全缓存,后续登录不再提供
- 提供 Account Authentication Modification Extension 让用户升级密码账号到 Sign in with Apple
- 定期检查 credential state,处理授权撤销的情况
- realUserStatus 为 “likelyReal” 时可以跳过 CAPTCHA 等额外验证
还有什么值得关注
- “Meet passkeys” 介绍了基于 FIDO 的无密码登录方案
- “Discover Sign in with Apple at Work & School” 覆盖了 Managed Apple ID 的支持
- Account Authentication Modification Extension 让密码→Sign in with Apple 的升级变得无缝
- 同时支持密码和 Sign in with Apple 的 App 应该优先展示已有凭据
WWDC 2022