Я создаю свое первое приложение на IOS, используя SwiftUI и Firebase для аутентификации и хранения
Для входа в систему я использую пользовательский интерфейс Firebase по умолчанию, который настраивается с помощью подкласса FUIAuthPickerViewController, называемого MyFUIAuthPickerViewController, как подробно описано в https://firebase.google.com/docs/auth/ios/firebaseui
DefaultUI инициализируется и отображается в файле делегата сцены.
// Create the SwiftUI view that provides the window contents.
//let contentView = ContentView()
self.authUI = _createAuthUI()
guard self.authUI != nil else {
print("No authUI")
return
}
self.authUI?.delegate = self
self.authUI?.shouldHideCancelButton = true
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
//window.rootViewController = UIHostingController(rootView: contentView)
window.rootViewController = UINavigationController(rootViewController: MyFUIAuthPickerViewController(authUI: authUI!))
self.window = window
window.makeKeyAndVisible()
}
Подкласс MyFUIAuthPickerViewController в настоящее время содержит не так много, но будет использоваться чтобы добавить фон по умолчанию на экран авторизации
import Foundation
import FirebaseUI
import Firebase
class MyFUIAuthPickerViewController: FUIAuthPickerViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
Для отслеживания входа пользователя в систему я использую объект Observable, называемый Sessionstore. Код, который я адаптировал из https://benmcmahen.com/authentication-with-swiftui-and-firebase/, в котором использовался протокол Bindable старого стиля
import Foundation
import SwiftUI
import Firebase
import Combine
class SessionStore : ObservableObject
{
@Published var user: AppUser?
var handle: AuthStateDidChangeListenerHandle?
func listen () {
// monitor authentication changes using firebase
handle = Auth.auth().addStateDidChangeListener { (auth, user) in
if let user = user {
// if we have a user, create a new user model
print("Got user: \(user) \(user.displayName!)")
self.user = AppUser(uid: user.uid,displayName: user.displayName, email: user.email)
} else {
// if we don't have a user, set our session to nil
self.user = nil
}
}
}
func signOut () -> Bool {
do {
try Auth.auth().signOut()
print("signed out")
self.user = nil
print("user object set to nil")
return true
} catch {
print("Problem encountered signing the user out")
return false
}
}
}
Объект окружения присутствует в моем представлении содержимого и моем объектеdelegate
scenedelegate
class SceneDelegate: UIResponder, UIWindowSceneDelegate, FUIAuthDelegate{
var window: UIWindow?
var authUI: FUIAuth?
@EnvironmentObject var appSession: SessionStore
contentview
import SwiftUI
import FirebaseUI
struct ContentView: View {
@EnvironmentObject var session: SessionStore
var body: some View {
Group{
if session.user != nil {
Text("Welcome \(session.user!.displayName!)")
} else {
Text("Please login")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
let nav = UINavigationController()
static var previews: some View {
ContentView().environmentObject(SessionStore())
}
}
В расширении на моем sceneDelegate я реализую необходимые функции Firebase. При успешном входе в систему я создаю новый объект appuser, который я помещаю в sessionStore, а затем меняю rootviewcontroller на contentview, передавая в environmentObject
Extension SceneDelegate {
func authUI(_ authUI: FUIAuth, didSignInWith user: User?, error: Error?) {
guard user != nil else {
print("No User")
return
}
print(user!.displayName!)
let user = AppUser(uid: user!.uid,displayName: user?.email,email: user?.displayName)
self.appSession.user = user
let contentView = ContentView()
self.window?.rootViewController = UIHostingController(rootView: contentView.environmentObject(SessionStore()))
self.window?.makeKeyAndVisible()
}
func authPickerViewController(for authUI: FUIAuth) -> FUIAuthPickerViewController {
return MyFUIAuthPickerViewController(authUI: authUI)
}
}
Теперь, когда я тестирую свое приложение, после ввода имени пользователя появляется следующая ошибка и пароль
Неустранимая ошибка: ObservableObject типа SessionStore не найден. В качестве предка этого представления может отсутствовать View.environmentObject (_ :) для SessionStore. File /BuildRoot/Library/Caches/com.apple.xbs/Sources/Monoceros_Sim/Monoceros-39.4.3/Core/EnvironmentObject.swift , строка 55
Я подозреваю, что это связано с тем, что de environmentObject теряется в MyFUIAuthPickerViewController между потоком из моего sceneDelegate в ContentView, но как я могу предотвратить это? Мне нужно как-то расширить MyFUIAuthPickerViewController, чтобы разрешить передачу environmentObject, но как?
Надеюсь, моя проблема ясна, и вы, ребята, можете помочь.