SwiftUI集成Apple SignIn遇代理方法未调用问题求助
解决SwiftUI中Apple SignIn代理方法未触发的问题
问题现象
在SwiftUI应用中集成Apple SignIn时,登录和权限申请界面可正常显示,但完成登录流程后,ASAuthorizationControllerDelegate的代理方法始终未被调用。
问题根源
- ViewModel生命周期过短:在
showAppleLoginView函数内创建的SignInWithAppleViewModel是局部变量,函数执行结束后会被ARC自动释放,导致代理回调时对象已不存在。 - 代理方法签名不匹配:原代码中的代理方法缺少Swift与Objective-C桥接所需的下划线参数标记,导致系统无法识别并触发回调。
- 缺少展示上下文配置:
ASAuthorizationController未设置presentationContextProvider,无法确定弹窗的展示载体。
修正方案
1. 修正ViewModel的代理方法签名
确保方法签名与系统要求完全一致:
import AuthenticationServices import SwiftUI class SignInWithAppleViewModel: NSObject, ASAuthorizationControllerDelegate { func authorizationController(_ controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { switch authorization.credential { case let appleIdCredential as ASAuthorizationAppleIDCredential: if let _ = appleIdCredential.email, let _ = appleIdCredential.fullName { registerNewUser(credential: appleIdCredential) } else { signInExistingUser(credential: appleIdCredential) } case let passwordCredential as ASPasswordCredential: print("\n ** ASPasswordCredential ** \n") signinWithUserNamePassword(credential: passwordCredential) default: break } } func authorizationController(_ controller: ASAuthorizationController, didCompleteWithError error: Error) { print("\n -- ASAuthorizationControllerDelegate -\(#function) -- \n") print(error) } // 原有业务方法保持不变 private func registerNewUser(credential: ASAuthorizationAppleIDCredential) { print(credential.email ?? "Email not available.") print(credential.fullName ?? "fullname not available") print(credential.fullName?.givenName ?? "givenName not available") print(credential.fullName?.familyName ?? "Familyname not available") print(credential.user) print(credential.identityToken?.base64EncodedString() ?? "Identity token not available") print(credential.authorizationCode?.base64EncodedString() ?? "Authorization code not available") } private func signInExistingUser(credential: ASAuthorizationAppleIDCredential) { print(credential.email ?? "Email not available.") print(credential.fullName ?? "fullname not available") print(credential.fullName?.givenName ?? "givenName not available") print(credential.fullName?.familyName ?? "Familyname not available") print(credential.user) print(credential.identityToken?.base64EncodedString() ?? "Identity token not available") print(credential.authorizationCode?.base64EncodedString() ?? "Authorization code not available") } private func signinWithUserNamePassword(credential: ASPasswordCredential) { print("\n ** ASPasswordCredential ** \n") print(credential.user) print(credential.password) } }
2. 调整ViewModel生命周期并配置展示上下文
将ViewModel作为视图的属性,同时让LoginView遵循ASAuthorizationControllerPresentationContextProviding协议:
import SwiftUI import AuthenticationServices struct LoginView: View { // 将ViewModel声明为视图属性,延长其生命周期 private let appleViewModel = SignInWithAppleViewModel() var body: some View { QuickSignInWithApple() .border(Color.black, width: 2) .background(Color.black) .cornerRadius(25) .frame(width: 280, height: 60, alignment: .center) .onTapGesture(perform: showAppleLoginView) } private func showAppleLoginView() { let provider = ASAuthorizationAppleIDProvider() let request = provider.createRequest() request.requestedScopes = [.fullName, .email] let controller = ASAuthorizationController(authorizationRequests: [request]) controller.delegate = appleViewModel // 设置展示上下文提供者 controller.presentationContextProvider = self controller.performRequests() } } // 实现展示上下文协议,指定弹窗的展示窗口 extension LoginView: ASAuthorizationControllerPresentationContextProviding { func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor { return UIApplication.shared.windows.first ?? ASPresentationAnchor() } }
关键要点
- 延长ViewModel生命周期:避免在函数内创建代理对象,确保回调时对象仍存在
- 严格匹配方法签名:Swift中Objective-C桥接的代理方法需要添加下划线参数标记
- 配置展示上下文:必须为
ASAuthorizationController指定弹窗的展示载体窗口
内容的提问来源于stack exchange,提问作者Peter Van de Put
相关产品推荐
相关产品推荐

