SwiftUI - Firebase Authentication - Environmental Object Doesn't Update on Sign In

swiftui and firebase
firebase auth ui
forgot password firebase swiftui
swift firebase authentication
firebase google sign in ios
firebase ios auth example
firebase phone authentication ios swift
firebase email authentication ios

I followed this tutorial to add Firebase user authentication to my SwiftUI project. When the user signs in or signs up, the sign in view is supposed to dissapear, and text displaying "Login Successful" should appear instead. However, this does not happen. It seems like the login / sign up process works, but the views don't change, and I suspect it may a problem with the EnvironmentalObject. Does anybody have some ideas about why this is happening? Thank you!

Here is some of my code -

AppDelegate.swift

...
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(SessionStore()))
        self.window = window
        window.makeKeyAndVisible()
    }
}
...

ContentView.swift

import SwiftUI

struct ContentView : View {

  @EnvironmentObject var session: SessionStore

  func getUser () {
      session.listen()
  }

  var body: some View {
      VStack {
          if (session.session == nil) {
              SignInView()
          } else {
              Text("Login successful!")
          }
    }.onAppear {
        self.getUser()
    }
  }
} 

SignInView.swift

import SwiftUI

struct SignInView : View {

    @State var email: String = ""
    @State var password: String = ""
    @State var loading = false
    @State var error = false

    @State var signInWorked = ""

    @EnvironmentObject var session: SessionStore

    func signIn () {
        loading = true
        error = false
        session.signIn(email: email, password: password) { (result, error) in
            self.loading = false
            if error != nil {
                self.error = true
            } else {
                self.email = ""
                self.password = ""
                self.signInWorked = "Signed In!"
            }
        }
    }

    func signUp () {
        loading = true
        error = false
        session.signUp(email: email, password: password) { (result, error) in
            self.loading = false
            if error != nil {
                self.error = true
            } else {
                self.email = ""
                self.password = ""
                self.signInWorked = "Signed In!"
            }
        }
    }

    var body: some View {
        VStack {
            TextField("Email Adress", text: $email)
            SecureField("Password", text: $password)
            if (error) {
                Text("ahhh crap")
            }
            Button(action: signIn) {
                Text("Sign in")
            }
            Button(action: signUp) {
               Text("Sign Up")
            }
            Text(signInWorked)
        }
    }
}

SessionStore.swift

import SwiftUI
import Firebase
import Combine

class SessionStore : ObservableObject {
var didChange = PassthroughSubject<SessionStore, Never>()
var session: User? { didSet { self.didChange.send(self) }}
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)")
            self.session = User(
                uid: user.uid,
                displayName: user.displayName,
                email: user.email)
        } else {
            // if we don't have a user, set our session to nil
            self.session = nil
        }
    }
}

func signUp(
    email: String,
    password: String,
    handler: @escaping AuthDataResultCallback
    ) {
    Auth.auth().createUser(withEmail: email, password: password, completion: handler)
}

func signIn(
    email: String,
    password: String,
    handler: @escaping AuthDataResultCallback
    ) {
    Auth.auth().signIn(withEmail: email, password: password, completion: handler)
}

func signOut () -> Bool {
    do {
        try Auth.auth().signOut()
        self.session = nil
        return true
    } catch {
        return false
    }
}

func unbind () {
    if let handle = handle {
        Auth.auth().removeStateDidChangeListener(handle)
    }
}
}

User.swift

import Foundation

class User {
var uid: String
var email: String?
var displayName: String?

init(uid: String, displayName: String?, email: String?) {
    self.uid = uid
    self.email = email
    self.displayName = displayName
}
}

You need to add the property wrapper @Published to your var session in SessionStore ensure that all views using it are refreshed when it changes. So change

var session: User? { didSet { self.didChange.send(self) }}

to

@Publishedvar session: User? { didSet { self.didChange.send(self) }}

See here for more info: https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data-between-views

Using Firebase Authentication with SwiftUI, This article is part of an ongoing series on Firebase and SwiftUI: When it does, we either create a new User model and assign it to our session to pass a SessionStore as an environment object (We'll get to this soon). Listening for authentication states with SwiftUI. Here’s our basic strategy: We want to create a SessionStore class which adheres to the BindableObject protocol. This class listens for authentication state changes (using a Firebase provided function) and updates our session information accordingly.

you can try this example iOS - swiftUI - Firebase Login complete setup this works perfectly and also does the same as you required. In this example after the login process is done in presenter modal, so when login is successful, it calls back the defined function and dismiss the login page. Hope this helps you.

Sign in with Apple using SwiftUI and Firebase, For a number of reasons, this is not what Firebase does. Instead, when you ask Firebase Auth to sign in a user anonymously, the SDK calls an using an Environment object (1); This allows us to force SwiftUI to re-create the  This is a tutorial on how to build your first SwiftUI based app with Firebase integration. All code is up to date with the current Xcode 11 GM release.

This is an answer specifically for those who are only not seeing it in canvas, but it works in simulator and device; you have to go to the YourView_Previews: section of your code (at the bottome) and add .environmentObject(SessionStore()) to the view being called in the preview (If your in ContentView.swift then it would be ContentView().environmentObject(SessionStore()) in the body of the Preview

Building Authentication in SwiftUI using Firebase Auth SDK & Sign , We will be utilizing Firebase Auth SDK to implement those features. the view using the environment object modifier inside the SceneDelegate . userInfo: [​NSLocalizedDescriptionKey: "Password and confirmation does not  Using Firebase Authentication with SwiftUI. Most iOS applications will probably require some form of authentication, and using Firebase is probably the easiest way to acheive this. This article will explain how you can add basic authentication to an app built with SwiftUI.

Ok this worked for me: if the @Published var isn't working and is only taking you to the HomeView (view you specify to go to if a user is signed in), you need to add a:

    func () { 
        session.signOut()
    }

put this in your HomeView()(not the body, but the struct) and create a signOut button that calls this func -- the problem is that your user remains signed in until you sign them out, and this easy fix should do it.

SwiftUI, SwiftUI | Login and Signup with Firebase Auth - Part 1 class, create an instance of it(1) and set it as an environment object of contentView(2) This delegate does not imply the connecting scene or session are new (see  3 SwiftUI - Firebase Authentication - Environmental Object Doesn't Update on Sign In Aug 26 '19 1 TypeError: firestore.collection is not a function (React / Redux / Firestore) Mar 14 1 “Failed to resolve: com.android.support:support-v4:26.0.0” and other similar errors on Gradle sync Jul 31 '17

Manage Users in Firebase, Get the currently signed-in user. The recommended way to get the current user is by setting a listener on the Auth object: Swift  We’re using Firebase Anonymous Authentication to get a unique ID for each user to make sure we can store data per user, and don’t accidentally mix up the tasks of person A and B (I’m pretty sure my kids would love to see their chores end up on my task list, but generally, this is not how task lists work - sorry to break the bad news to

Handle Firebase iOS Auth Errors, Please report the error with the entire NSError object. token) is already in use by an existing account, that cannot be authenticated with this sign-in method. This, in turn, rerenders our FirebaseImage now using the firebase image instead of the placeholder. You can see the entire code in the julienne-swift example repo. This article is part of an ongoing series on Firebase and SwiftUI: Using Firebase Authentication with SwiftUI; Displaying Firebase Images wih SwiftUI

How To Build A Firebase App With SwiftUI - Flawless iOS, While you're on Firebase, setup the authentication for email and password and set up a Realtime Database with the following rules. These allow  It supports authentication using passwords, phone numbers, popular federated identity providers like Google, Facebook and Twitter, and more. Firebase Authentication integrates tightly with other Firebase services, and it leverages industry standards like OAuth 2.0 and OpenID Connect, so it can be easily integrated with your custom backend.

Comments
  • I have the same problem too. The app works correctly in simulator and device but not into the Canvas
  • Well, in my case, it occurs in all three. The sign in is successful, but the view doesn't dissapear.
  • yes the same for me. The sign works properly but the view doesn't disappear in canvas (simulator and device work).
  • pod 'CombineFirebase/Auth' will drastically simplify this.