You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 07:25:20