SwiftUI中Google登录导航异常:取消登录返回根视图
SwiftUI中Google登录取消后保留注册页面的解决方案
问题根源
你遇到的取消登录后跳回根视图的问题,通常是因为未正确指定Google登录弹窗的presentingViewController,或者使用了不兼容SwiftUI的旧版登录API,导致登录流程结束后导航栈被意外重置。
方案1:使用Google Sign-In 7.0+的SwiftUI原生异步API
Google Sign-In iOS SDK 7.0及以上提供了适配SwiftUI的异步方法signInWithPresenting,无需手动获取ViewController,能自动适配当前视图上下文,取消登录后不会跳转回根视图。
步骤:
- 确保你的
GoogleSignInPod版本≥7.0 - 在ViewModel中实现异步登录方法:
class AuthViewModel: ObservableObject { func signInWithGoogle() async { do { // 自动适配当前SwiftUI视图上下文 let signInResult = try await GIDSignIn.sharedInstance.signInWithPresenting(presenting: nil) let googleUser = signInResult.user // 提取Google凭证并传给Firebase guard let idToken = googleUser.idToken?.tokenString else { return } let accessToken = googleUser.accessToken.tokenString let firebaseCredential = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: accessToken) // Firebase验证登录 let authResult = try await Auth.auth().signIn(with: firebaseCredential) // 处理登录成功逻辑(比如导航到首页) } catch { // 登录取消或失败时,停留在当前页面 print("登录操作终止:\(error.localizedDescription)") } } }
- 在注册第三页的SwiftUI视图中调用该方法:
struct SignUpThirdPage: View { @EnvironmentObject var authVM: AuthViewModel var body: some View { Button("通过Google完成注册") { Task { await authVM.signInWithGoogle() } } } }
方案2:手动获取当前ViewController作为弹窗宿主
如果无法升级SDK版本,可以通过环境变量注入当前ViewController,确保Google登录弹窗从当前注册页面的VC弹出,取消后不会影响导航栈。
步骤:
- 创建获取ViewController的工具代码:
// 用于获取当前ViewController的ViewModifier struct ViewControllerInjector: UIViewControllerRepresentable { @Binding var viewController: UIViewController? func makeUIViewController(context: Context) -> UIViewController { UIViewController() } func updateUIViewController(_ uiViewController: UIViewController, context: Context) { DispatchQueue.main.async { viewController = uiViewController.parent } } } // 扩展环境变量,方便在SwiftUI视图中获取VC extension EnvironmentValues { private struct CurrentVCKey: EnvironmentKey { static var defaultValue: UIViewController? = nil } var currentViewController: UIViewController? { get { self[CurrentVCKey.self] } set { self[CurrentVCKey.self] = newValue } } } extension View { func injectCurrentViewController() -> some View { let vcBinding = Binding<UIViewController?>( get: { self.environment(\.currentViewController).wrappedValue }, set: { self.environment(\.currentViewController, $0) } ) return self.background(ViewControllerInjector(viewController: vcBinding)) } }
- 在注册流程的根导航视图中注入VC:
struct SignUpNavigationStack: View { var body: some View { NavigationStack { SignUpFirstPage() .navigationDestination(for: SignUpStep.self) { step in switch step { case .second: SignUpSecondPage() case .third: SignUpThirdPage() } } } .injectCurrentViewController() } }
- 在第三页视图中调用登录时指定presentingVC:
struct SignUpThirdPage: View { @Environment(\.currentViewController) var currentVC @EnvironmentObject var authVM: AuthViewModel var body: some View { Button("通过Google完成注册") { authVM.signInWithGoogle(presentingVC: currentVC) } } }
- ViewModel中的登录方法:
class AuthViewModel: ObservableObject { func signInWithGoogle(presentingVC: UIViewController?) { guard let vc = presentingVC else { return } let config = GIDConfiguration(clientID: FirebaseApp.app()?.options.clientID ?? "") GIDSignIn.sharedInstance.signIn(with: config, presenting: vc) { user, error in if let error = error { // 取消登录时停留在当前页面 print("登录操作终止:\(error.localizedDescription)") return } guard let auth = user?.authentication else { return } let credential = GoogleAuthProvider.credential(withIDToken: auth.idToken!, accessToken: auth.accessToken!) Auth.auth().signIn(with: credential) { result, error in // 处理Firebase登录结果 } } } }
关键注意事项
- 方案1是官方推荐的SwiftUI适配方案,代码更简洁且不易出错
- 确保
Info.plist中的Google登录配置(URL Scheme等)正确,避免其他跳转异常 - 测试时要覆盖取消登录的场景,确认导航栈未被重置
内容的提问来源于stack exchange,提问作者Swiss
相关产品推荐
相关产品推荐

