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

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,能自动适配当前视图上下文,取消登录后不会跳转回根视图。

步骤:

  1. 确保你的GoogleSignIn Pod版本≥7.0
  2. 在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)")
        }
    }
}
  1. 在注册第三页的SwiftUI视图中调用该方法:
struct SignUpThirdPage: View {
    @EnvironmentObject var authVM: AuthViewModel
    
    var body: some View {
        Button("通过Google完成注册") {
            Task {
                await authVM.signInWithGoogle()
            }
        }
    }
}

方案2:手动获取当前ViewController作为弹窗宿主

如果无法升级SDK版本,可以通过环境变量注入当前ViewController,确保Google登录弹窗从当前注册页面的VC弹出,取消后不会影响导航栈。

步骤:

  1. 创建获取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))
    }
}
  1. 在注册流程的根导航视图中注入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()
    }
}
  1. 在第三页视图中调用登录时指定presentingVC:
struct SignUpThirdPage: View {
    @Environment(\.currentViewController) var currentVC
    @EnvironmentObject var authVM: AuthViewModel
    
    var body: some View {
        Button("通过Google完成注册") {
            authVM.signInWithGoogle(presentingVC: currentVC)
        }
    }
}
  1. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 22:20:35