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
相关产品推荐
相关产品推荐

