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

SwiftUI集成Apple SignIn遇代理方法未调用问题求助

解决SwiftUI中Apple SignIn代理方法未触发的问题

问题现象

在SwiftUI应用中集成Apple SignIn时,登录和权限申请界面可正常显示,但完成登录流程后,ASAuthorizationControllerDelegate的代理方法始终未被调用。

问题根源

  1. ViewModel生命周期过短:在showAppleLoginView函数内创建的SignInWithAppleViewModel是局部变量,函数执行结束后会被ARC自动释放,导致代理回调时对象已不存在。
  2. 代理方法签名不匹配:原代码中的代理方法缺少Swift与Objective-C桥接所需的下划线参数标记,导致系统无法识别并触发回调。
  3. 缺少展示上下文配置: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 23:50:28