如何从ASWebAuthenticationSession回调回到SwiftUI视图?
实现ASWebAuthenticationSession结果回传至SwiftUI视图
要完成从ASWebAuthenticationSession的completion handler携带认证code返回SwiftUI视图并处理,核心是利用ObservableObject的响应式属性传递状态,具体步骤如下:
1. 改造AuthSession类,添加响应式状态
因为AuthSession已经实现了ObservableObject,可以通过@Published属性将认证结果暴露给SwiftUI视图:
class AuthSession: NSObject, ObservableObject, ASWebAuthenticationPresentationContextProviding { // 用于存储认证code @Published var authCode: String? // 标记认证是否成功 @Published var isAuthenticated = false // 存储认证错误信息 @Published var authError: Error? private(set) var webAuthSession: ASWebAuthenticationSession! override init() { super.init() webAuthSession = ASWebAuthenticationSession( url: AuthHandler.shared.signInURL()!, callbackURLScheme: "your-scheme", // 替换为实际的回调scheme completionHandler: { [weak self] callbackURL, error in guard let self = self else { return } if let error = error { self.authError = error self.isAuthenticated = false return } // 从回调URL中解析认证code if let callbackURL = callbackURL, let components = URLComponents(url: callbackURL, resolvingAgainstBaseURL: false), let codeItem = components.queryItems?.first(where: { $0.name == "code" }), let code = codeItem.value { self.authCode = code self.isAuthenticated = true } else { self.isAuthenticated = false self.authError = NSError(domain: "AuthError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无法获取认证code"]) } } ) webAuthSession.presentationContextProvider = self webAuthSession.prefersEphemeralWebBrowserSession = true } func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { // 返回当前的主窗口,确保弹窗正确显示 return UIApplication.shared.windows.first(where: { $0.isKeyWindow }) ?? ASPresentationAnchor() } }
2. 调整SignInView,正确持有AuthSession并监听状态
SwiftUI视图需要持有AuthSession实例,并通过监听@Published属性的变化来触发后续逻辑:
struct SignInView: View { @EnvironmentObject var signedIn: UIState // 使用@StateObject持有AuthSession实例,确保生命周期与视图一致 @StateObject private var authSession = AuthSession() var body: some View { Button("开始认证") { authSession.webAuthSession.start() } // 监听认证状态变化 .onReceive(authSession.$isAuthenticated) { isAuthenticated in guard isAuthenticated else { // 处理认证失败逻辑,比如展示错误 if let error = authSession.authError { print("认证失败: \(error.localizedDescription)") } return } // 认证成功,拿到code执行后续处理 if let code = authSession.authCode { signedIn.isSignedIn = true // 这里可以调用API交换token等逻辑 print("获取到认证code: \(code)") } } } }
关键说明
@StateObject:确保AuthSession实例在视图生命周期内唯一,避免重复创建会话@Published属性:当completion handler中更新这些属性时,SwiftUI会自动刷新视图并触发后续逻辑- 回调URL解析:要确保
callbackURLScheme与认证服务配置的一致,才能正确获取到包含code的回调URL - 弱引用
[weak self]:避免completion handler持有AuthSession导致的循环引用
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

