Ios 使用Google登录和SwiftUI检查用户身份验证

Ios 使用Google登录和SwiftUI检查用户身份验证,ios,swift,firebase-authentication,swiftui,combine,Ios,Swift,Firebase Authentication,Swiftui,Combine,我已经使用Google登录成功地在我的应用程序中设置了身份验证,我可以返回Firebase用户。我正在尝试设置一个登录屏幕,该屏幕仅在没有经过身份验证的Firebase用户时显示,但是使用我的当前代码,即使我始终返回经过身份验证的用户,登录屏幕始终可见 我已经在AppDelegate func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) { // ...

我已经使用Google登录成功地在我的应用程序中设置了身份验证,我可以返回Firebase用户。我正在尝试设置一个登录屏幕,该屏幕仅在没有经过身份验证的Firebase用户时显示,但是使用我的当前代码,即使我始终返回经过身份验证的用户,登录屏幕始终可见

我已经在
AppDelegate

func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) {
      // ...
      if let error = error {
        print(error.localizedDescription)
        return
      }

      guard let authentication = user.authentication else { return }
      let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
                                                        accessToken: authentication.accessToken)
      // ...
        Auth.auth().signIn(with: credential) { (authResult, error) in
            if let error = error {
                print(error.localizedDescription)
                return
            }
            let session = FirebaseSession.shared

            if let user = Auth.auth().currentUser {
                session.user = User(uid: user.uid, displayName: user.displayName, email: user.email)
                print("User sign in successful: \(user.email!)")
            }
        }
    }
以及
中的几行使用选项完成启动,这些选项设置my
ObservableObject的
isLoggedIn
属性
FirebaseSession

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        FirebaseApp.configure()

        let auth = Auth.auth()

        if auth.currentUser != nil {
            FirebaseSession.shared.isLoggedIn = true
            print(auth.currentUser?.email!)
        } else {
            FirebaseSession.shared.isLoggedIn = false
        }

        //Cache
        let settings = FirestoreSettings()
        settings.isPersistenceEnabled = false

        GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
        GIDSignIn.sharedInstance().delegate = self

        return true
    }
我的
可观察对象

class FirebaseSession: ObservableObject {

        static let shared = FirebaseSession()
        init () {}

        //MARK: Properties
        @Published var user: User?
        @Published var isLoggedIn: Bool?

        @Published var items: [Thought] = []

        var ref: DatabaseReference = Database.database().reference(withPath: "\(String(describing: Auth.auth().currentUser?.uid ?? "Error"))")

        //MARK: Functions
        func listen() {
            _ = Auth.auth().addStateDidChangeListener { (auth, user) in

                if auth.currentUser != nil {
                    self.isLoggedIn = true
                }

                if let user = user {
                    self.user = User(uid: user.uid, displayName: user.displayName, email: user.email)
                } else {
                    self.user = nil
                }
            }
        }
    }
struct AppView: View {

    @ObservedObject var session = FirebaseSession.shared

    @State var modalSelection = 1
    @State var isPresentingAddThoughtModal = false

    var body: some View {
        NavigationView {
            Group {
                if session.isLoggedIn == true {
                    ThoughtsView()
                } else {
                    SignInView()
                }
            }
        }
    }
}
最后,我在我的应用程序的主视图中执行身份验证检查,通过我的
ObservedObject访问
FirebaseSession

class FirebaseSession: ObservableObject {

        static let shared = FirebaseSession()
        init () {}

        //MARK: Properties
        @Published var user: User?
        @Published var isLoggedIn: Bool?

        @Published var items: [Thought] = []

        var ref: DatabaseReference = Database.database().reference(withPath: "\(String(describing: Auth.auth().currentUser?.uid ?? "Error"))")

        //MARK: Functions
        func listen() {
            _ = Auth.auth().addStateDidChangeListener { (auth, user) in

                if auth.currentUser != nil {
                    self.isLoggedIn = true
                }

                if let user = user {
                    self.user = User(uid: user.uid, displayName: user.displayName, email: user.email)
                } else {
                    self.user = nil
                }
            }
        }
    }
struct AppView: View {

    @ObservedObject var session = FirebaseSession.shared

    @State var modalSelection = 1
    @State var isPresentingAddThoughtModal = false

    var body: some View {
        NavigationView {
            Group {
                if session.isLoggedIn == true {
                    ThoughtsView()
                } else {
                    SignInView()
                }
            }
        }
    }
}
如上所述,我的支票似乎不起作用。即使我的用户已通过身份验证,
SignInView
始终可见

如何在每次加载应用程序时成功检查用户身份验证

更新

我现在可以在应用程序加载时检查身份验证,但在实施Sohil的解决方案后,我没有观察到我的
observeObject
FirebaseSession
的实时更改。我希望观察对
FirebaseSession
的更改,以便新用户登录后,
AppView
的主体将被重新绘制并呈现
ThoughtsView
而不是
SignenView
。目前,我必须重新加载应用程序,以便在验证后进行检查


如何从
AppView
观察对
FirestoreSession
的更改?

您的问题在于访问对象及其值。意味着,在
AppDelegate.swift
文件中,您正在创建
FirebaseSession
的对象并分配值,但在
AppView
中,您将再次创建
FirebaseSession
的新对象,该对象将创建类的新实例,并且所有值都将替换为默认值

因此,您需要在整个应用程序生命周期中使用相同的对象,这可以通过全局定义
let session=FirebaseSession()
或创建一个来完成,如下图所示

class FirebaseSession: ObservableObject {

    static let shared = FirebaseSession()

    private init () {}

    //Properties...
    //Functions...
}
然后您可以访问
共享的
对象,如下所示:

FirebaseSession.shared.properties

这样,您分配的值将在应用程序生命周期中保留。

您需要这样做。我没有试着运行这个,所以我不确定是否有任何打字错误

class SessionStore : ObservableObject {
  @Published var session: FIRUser?
  var isLoggedIn: Bool { session != nil}
  var handle: AuthStateDidChangeListenerHandle?

  init () {
    handle = Auth.auth().addStateDidChangeListener { (auth, user) in
      if let user = user {
        self.session = user
     } else {
        self.session = nil
      }
    }
  }

  deinit {
    if let handle = handle {
       Auth.auth().removeStateDidChangeListener(handle)
    }
  }
}
在您的组件中:


struct AppView: View {
    @ObservedObject var session = SessionStore()

    var body: some View {
        Group {
          if session.isLoggedIn {
            ...
          } else {
            ...
          }
      }
    }
}

注意这里重要的一点是,正在更改的对象是
@Published
。这就是您在视图中接收更新的方式。

我不知道它是否对您有用,但我现在阅读了您的问题,因为我正在为类似问题找到解决方案,所以我找到了它,我将与您分享

我想用一个代表。因此,我在我的
AppDelegate
类中创建了一个名为
ApplicationLoginDelegate
的协议

我用以下方式定义协议:

protocol ApplicationLoginDelegate: AnyObject {
    func loginDone(userDisplayName: String)
}
并在
AppDelegate
类中定义
loginDelegate

weak var loginDelegate: ApplicationLoginDelegate?
您可以在didSignIn func中调用委托func

Auth.auth().signIn(with: credential) { (res, error) in

      if let err = error {
          print(err.localizedDescription)
          return
      } else {
          self.loginDelegate?.loginDone(userDisplayName: (res?.user.displayName)!)
      }
  }
因此,在ScenedLegate中,您可以使用我向您展示的代理:

class SceneDelegate: UIResponder, UIWindowSceneDelegate, ApplicationLoginDelegate {

var window: UIWindow?
var eventsVM: EventsVM?

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

    // Set the app login delegate
    (UIApplication.shared.delegate as! AppDelegate).loginDelegate = self

    // Environment Objects
    let eventsVM = EventsVM()

    self.eventsVM = eventsVM

    // Create the SwiftUI view that provides the window contents.
    let contentView = ContentView()
        .environmentObject(eventsVM)

    // Use a UIHostingController as window root view controller.
    [...]
}

func loginDone(userDisplayName: String) {
    guard let eventsVM = self.eventsVM else { return }
    eventsVM.mainUser = User(displayName: userDisplayName)
}
因此,当您更新了环境对象时,它本身就是一个@Publisced对象(例如用户对象),您可以在定义和调用环境对象的任何地方接收更新


就这样

此解决方案的工作原理是,我现在能够从
AppView
成功检查身份验证,但是我无法像我需要的那样观察到
AppView
对我的
observeObject
FirebaseSession
的更改。我的目标是,一旦新用户登录,
FirebaseSession.isLoggedIn
将切换,从而导致重新绘制
AppView
。使用上述解决方案,我必须重新加载应用程序才能进行检查,因为没有观察到
FirebaseSession