Sign In with Apple跨设备报错No Credential Available的问题求助
Sign In with Apple 跨设备报错 "No credentials available for login" 解决方案
错误原因
这个报错来自ASAuthorizationPasswordProvider的请求,该请求用于读取设备钥匙串中已保存的Apple登录凭证。其他设备未保存对应账号的密码凭证时,该请求会失败;而你的代码同时发起了Apple ID授权和密码凭证请求,系统可能优先处理密码请求,失败后直接返回错误,未触发Apple ID登录界面。
修复步骤及代码修改
1. 拆分请求逻辑,优先处理密码凭证,失败后发起Apple ID授权
修改按钮点击方法,先尝试钥匙串密码凭证登录,失败后再触发Apple ID授权流程:
@objc private func appleSignInPressed() { // 先尝试钥匙串中的密码凭证登录 let passwordProvider = ASAuthorizationPasswordProvider() let passwordRequest = passwordProvider.createRequest() let passwordController = ASAuthorizationController(authorizationRequests: [passwordRequest]) passwordController.delegate = self passwordController.presentationContextProvider = self passwordController.performRequests() }
2. 优化错误代理,处理凭证不存在的情况
在错误代理中判断错误码,当遇到credentialsNotFound时,自动发起Apple ID授权:
extension WelcomeViewController: ASAuthorizationControllerDelegate { func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { switch authorization.credential { case let passwordCredential as ASPasswordCredential: // 钥匙串凭证登录成功 let username = passwordCredential.user let password = passwordCredential.password viewModel.didTouchLoginButton(with: username, and: password, feeds: [], referralLink: nil) case let credentials as ASAuthorizationAppleIDCredential: // Apple ID授权成功 let givenName = credentials.fullName?.givenName ?? "user" // 仅首次授权时会返回email,后续授权需从服务器或本地存储获取 if let email = credentials.email { print("\(givenName) \(email)") // 保存userID用于后续状态检查 UserDefaults.standard.set(credentials.user, forKey: "AppleUserID") } else { // 非首次授权,用userID去服务器获取用户信息 viewModel.didAppleSignIn(withUserID: credentials.user) } default: startSignUpFlow() } } func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) { guard let authError = error as? ASAuthorizationError else { print("FAILED: \(error.localizedDescription)") return } switch authError.code { case .canceled: // 用户取消操作,无需处理 break case .credentialsNotFound: // 钥匙串无凭证,发起Apple ID授权请求 let appleIDProvider = ASAuthorizationAppleIDProvider() let appleIDRequest = appleIDProvider.createRequest() appleIDRequest.requestedScopes = [.email, .fullName] let appleIDController = ASAuthorizationController(authorizationRequests: [appleIDRequest]) appleIDController.delegate = self appleIDController.presentationContextProvider = self appleIDController.performRequests() default: print("FAILED: \(authError.localizedDescription)") } } }
3. 确保展示上下文实现正确
添加ASAuthorizationControllerPresentationContextProviding扩展,返回正确的窗口用于展示登录弹窗:
extension WelcomeViewController: ASAuthorizationControllerPresentationContextProviding { func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor { // 返回当前控制器所在的窗口,适配iOS 13+场景 return view.window ?? UIWindow(frame: UIScreen.main.bounds) } }
4. 处理已授权用户的自动登录
在控制器加载时,检查已保存的Apple用户ID的凭证状态,实现自动登录:
override func viewDidLoad() { super.viewDidLoad() let appleIDProvider = ASAuthorizationAppleIDProvider() if let userID = UserDefaults.standard.string(forKey: "AppleUserID") { appleIDProvider.getCredentialState(forUserID: userID) { [weak self] state, error in DispatchQueue.main.async { guard let self = self else { return } switch state { case .authorized: // 用户已授权,直接发起登录请求 self.viewModel.didAppleSignIn(withUserID: userID) case .revoked, .notFound: // 凭证已失效或未找到,清除本地存储 UserDefaults.standard.removeObject(forKey: "AppleUserID") default: break } } } } }
额外注意事项
- 仅用户首次授权时,
ASAuthorizationAppleIDCredential会返回email和fullName;后续授权需通过保存的userID从服务器获取用户信息。 - 确保你的App已在Apple开发者后台配置好Sign In with Apple功能,且Bundle ID匹配。
内容的提问来源于stack exchange,提问作者tHatpart
相关产品推荐
相关产品推荐

