Как настроить Firebase Google для входа в систему 6.0.2 с использованием архитектуры SwiftUI 2.0?

# #swift #firebase #swiftui #google-signin

Вопрос:

Я пытаюсь настроить последний гугл-дизайн с помощью SwiftUI. Официальная документация 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 но нет примера кода, показывающего, как это сделать правильно.

Ответ №1:

Вероятно, вы захотите запустить этот код в результате действия, которое выполняет пользователь. Button Например , после нажатия кнопки «а».

Хитрая часть будет заключаться в том, что GIDSignIn.sharedInstance.signIn UIViewController для своего presenting аргумента требуется a, что не обязательно просто получить в SwiftUI. Вы можете использовать a 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)
            }
        }
    }
}
 

Комментарии:

1. Спасибо за быстрый ответ! Насколько я понимаю, в моем случае нет другого способа, кроме как использовать uiviewcontrollerпредставляемый?

2. Вы также можете попытаться получить ссылку на контроллер представления из window , но это может быть проблематично в современных приложениях на основе сцен, где не обязательно одно окно. Другой вариант-использовать что-то вроде SwiftUI-Introspect, но лично я предпочел бы использовать uiviewcontrollerпредставляемый, чем вводить зависимость от третьей стороны.