Ios 使用Google登录和SwiftUI检查用户身份验证
我已经使用Google登录成功地在我的应用程序中设置了身份验证,我可以返回Firebase用户。我正在尝试设置一个登录屏幕,该屏幕仅在没有经过身份验证的Firebase用户时显示,但是使用我的当前代码,即使我始终返回经过身份验证的用户,登录屏幕始终可见 我已经在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?) { // ...
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!)")
}
}
}
以及中的几行使用选项完成启动,这些选项设置myObservableObject的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
。