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

SwiftUI生命周期iOS应用集成GoogleSignIn:如何设置presentingViewController

在SwiftUI生命周期应用中集成GoogleSignIn:解决presentingViewController的问题

嘿,这个问题我当初在SwiftUI项目里集成Google登录时也卡了好久!毕竟SwiftUI生命周期里确实没有传统的ViewController、AppDelegate这些东西,那怎么给GoogleSignIn SDK提供展示用的控制器呢?给你分享两个我亲测有效的方法:

方法一:用UIViewControllerRepresentable做桥接控制器

这是最贴合SwiftUI设计思路的方法——我们自定义一个UIViewControllerRepresentable类型,把它作为GoogleSignIn的“容器”ViewController,这样就能直接把这个容器VC传给SDK了。

示例代码:

import SwiftUI
import GoogleSignIn

// 自定义桥接VC
struct GoogleSignInContainer: UIViewControllerRepresentable {
    @Binding var isUserSignedIn: Bool
    
    func makeUIViewController(context: Context) -> UIViewController {
        let containerVC = UIViewController()
        // 直接把这个容器VC设置为GoogleSignIn的presentingViewController
        GIDSignIn.sharedInstance().presentingViewController = containerVC
        // 设置登录回调代理
        GIDSignIn.sharedInstance().delegate = context.coordinator
        return containerVC
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
    
    // 用Coordinator处理登录回调
    class Coordinator: NSObject, GIDSignInDelegate {
        var parent: GoogleSignInContainer
        
        init(parent: GoogleSignInContainer) {
            self.parent = parent
        }
        
        func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
            if let error = error {
                print("Google登录失败:\(error.localizedDescription)")
                return
            }
            // 登录成功,更新SwiftUI状态
            parent.isUserSignedIn = true
            // 这里可以获取用户信息:user.profile?.name、user.profile?.email等
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }
}

// 在你的主视图中使用
struct ContentView: View {
    @State private var isSignedIn = false
    
    var body: some View {
        if isSignedIn {
            Text("🎉 登录成功!")
                .font(.largeTitle)
        } else {
            VStack {
                GoogleSignInContainer(isUserSignedIn: $isSignedIn)
                    .frame(width: 0, height: 0) // 隐藏容器VC的视图
                
                Button("🔑 使用Google登录") {
                    // 触发登录流程
                    GIDSignIn.sharedInstance().signIn()
                }
                .buttonStyle(.borderedProminent)
            }
        }
    }
}

方法二:直接获取当前顶层ViewController

如果你觉得桥接VC有点繁琐,可以通过扩展UIApplication来获取当前应用的顶层ViewController,直接把它传给GoogleSignIn SDK。这种方法更灵活,适合快速集成。

步骤1:添加顶层VC扩展

import UIKit

extension UIApplication {
    func getTopViewController() -> UIViewController? {
        // 获取当前活跃的窗口场景
        guard let windowScene = connectedScenes
            .filter({ $0.activationState == .foregroundActive })
            .first as? UIWindowScene,
              let keyWindow = windowScene.windows.first(where: { $0.isKeyWindow }) else {
            return nil
        }
        
        // 递归找到最顶层的VC
        var topVC = keyWindow.rootViewController
        while let presentedVC = topVC?.presentedViewController {
            topVC = presentedVC
        }
        
        return topVC
    }
}

步骤2:在SwiftUI中使用

import SwiftUI
import GoogleSignIn

struct ContentView: View {
    @State private var isSignedIn = false
    
    var body: some View {
        VStack {
            if isSignedIn {
                Text("登录成功,欢迎回来!")
            } else {
                Button("使用Google登录") {
                    guard let topVC = UIApplication.shared.getTopViewController() else {
                        print("无法获取顶层ViewController")
                        return
                    }
                    
                    // GoogleSignIn 6.0+推荐使用这个方法
                    GIDSignIn.sharedInstance().signIn(withPresenting: topVC) { result, error in
                        if let error = error {
                            print("登录出错:\(error)")
                            return
                        }
                        
                        guard let user = result?.user else { return }
                        print("登录用户:\(user.profile?.name ?? "")")
                        isSignedIn = true
                    }
                }
            }
        }
    }
}

重要注意事项

  • 确保你已经在Info.plist中配置了GoogleSignIn的必要信息:包括CLIENT_ID、REVERSED_CLIENT_ID,以及URL Scheme(对应REVERSED_CLIENT_ID)。
  • 如果你使用的是GoogleSignIn 6.x版本,API有较大更新,比如signIn(withPresenting:)替代了旧版的signIn()方法,记得适配版本。
  • 用顶层VC的方法时,如果当前有sheet或弹窗弹出,获取到的顶层VC就是那个弹窗VC,这是正确的——Google登录视图会自动在当前最上层的界面展示。

内容的提问来源于stack exchange,提问作者NSRover

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 22:47:37