如何使用 SwiftUI 2.0 架构设置 Firebase Google SignIn 6.0.2?

How to set up Firebase Google SignIn 6.0.2 using SwiftUI 2.0 architecture?

我正在尝试使用 SwiftUI 设置最新的 GoogleSignIn。官方 Firebase 文档提供了为 UIKit、ViewControllers 和 AppDelegate 设计的过时方法,因此根本没有办法找出需要什么变通方法才能使其工作。我能够实现 UIApplicationDelegateAdaptor 以访问 didFinishLaunchingWithOptions 方法来配置 FirebaseApp 和 GIDSignIn。 在遵循此文档时:https://firebase.google.com/docs/auth/ios/google-signin 我最终坚持了第 4 步。不清楚我必须在哪里使用此代码或如何将其集成到 SwiftUI 范例中:

guard let clientID = FirebaseApp.app()?.options.clientID else { return }

// Create Google Sign In configuration object.
let config = GIDConfiguration(clientID: clientID)

// Start the sign in flow!
GIDSignIn.sharedInstance.signIn(with: config, presenting: self) { [unowned self] user, error in

  if let error = error {
    // ...
    return
  }

  guard
    let authentication = user?.authentication,
    let idToken = authentication.idToken
  else {
    return
  }

  let credential = GoogleAuthProvider.credential(withIDToken: idToken,
                                                 accessToken: authentication.accessToken)

  // ...
}

我从 Google 了解到此指南:https://developers.google.com/identity/sign-in/ios/quick-migration-guide 但没有代码示例说明如何正确执行此操作。

您可能希望 运行 该代码作为用户执行操作的结果。例如按下 Button 之后。

棘手的部分将是 GIDSignIn.sharedInstance.signIn 需要一个 UIViewController 作为它的 presenting 参数,这在 SwiftUI 中不一定是直接获得的。您可以使用 UIViewControllerRepresentable 来获取对层次结构中可以呈现的视图控制器的引用。

class LoginManager : ObservableObject {
    var viewController : UIViewController?
    
    func runLogin() {
        guard let viewController = viewController else {
            fatalError("No view controller")
        }
        
        //Other GIDSignIn code here. Use viewController for the `presenting` argument
    }
}

struct DummyViewController : UIViewControllerRepresentable {
    var loginManager : LoginManager
    
    func makeUIViewController(context: Context) -> some UIViewController {
        let vc = UIViewController()
        loginManager.viewController = vc
        return vc
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        
    }
}

struct ContentView : View {
    @StateObject private var loginManager = LoginManager()
    
    var body: some View {
        VStack(spacing: 0) {
            Button(action: {
                loginManager.runLogin()
            }) {
                Text("Login")
                DummyViewController(loginManager: loginManager)
                    .frame(width: 0, height: 0)
            }
        }
    }
}