skip to Main Content

currently I am implementing an application and using Firebase authentication
I would like to make a pop up which appears inside the app if the connectivity got lost
unfortunately when I cut the network connectivity, the application logs the user out which I do not want
also Xcode doesn’t recognize the auth.setPersistence(.local) method

this is my content view which checks if the user is logged in:

struct ContentView: View {
    @EnvironmentObject var viewModel: AppViewModel
    
    var body: some View {
        NavigationView{
            if viewModel.loggedIn{
                HomeView()
            } else {
            LoginView()
            }
        }
        .onAppear {
           viewModel.loggedIn = viewModel.isSignedIN
         }
    }
}

the loggedIn var is declared in this way:

@Published var loggedIn = false

these are the methods used to log in, sign up and log out:

  /// This function connects to the Firebase Authentication database and logs the user in
    /// - Parameters:
    ///   - email: e-mail address entered by user in order to log in
    ///   - password: password entered by user in order to log in
    func logIn(email: String, password: String) async throws {
        mail = email
        let authRes = try await auth.signIn(withEmail: email, password: password)
        loggedIn = true
    }
    
    
    /// This function signs the user up
    /// - Parameters:
    ///   - email: e-mail used for signing up
    ///   - password: password used for signing up
    func signUp(email: String, password: String) async throws {
        mail = email
        let authRes = try await auth.createUser(withEmail: email, password: password)
        loggedIn = true
    }
    
    
    /// This function logs the user out
    func logOut() {
        try? auth.signOut()
        self.loggedIn = false
        self.eventlist.removeAll()
    }

I tried saving the loggedIn variable in the user defaults but it is not working unfortunately

does anyone have an idea which way is the best to handle this problem?

2

Answers


  1. Instead of creating your own logic for maintain the logged in status you can use.

    handle = Auth.auth().addStateDidChangeListener { auth, user in
      isLoggedIn = user != nil
    }
    

    https://firebase.google.com/docs/auth/ios/start

    Then create an

    @AppStorage var isloggedIn:Bool = false
    

    This will hold the true state of your user, you don’t have to and should not alter this variable any other way.

    Also, make sure you remove the listener when not in use such as deinit

    Auth.auth().removeStateDidChangeListener(handle!)
    
    Login or Signup to reply.
  2. No need to implement this yourself (and under no circumstances store any sensitive information in UserDefaults, as this is not secure), as the Firebase SDK takes care of this for you.

    In fact, we store the signed in user in the Keychain and retrieve it as soon as you instantiate the Auth object.

    So all you have to do is initialise Firebase Auth once your app has finished loading, and then set up an authentication state listener to be notified whenever the user signs in or out.

    Here is a code snippet for an AuthenticationViewModel that shows how to do this in SwiftUI:

    @MainActor
    class AuthenticationViewModel: ObservableObject {
      @Published var email = ""
      @Published var password = ""
      @Published var confirmPassword = ""
    
      @Published var authenticationState: AuthenticationState = .unauthenticated
      @Published var errorMessage = ""
      @Published var user: User?
      @Published var displayName = ""
    
      init() {
        registerAuthStateHandler()
      }
    
      private var authStateHandler: AuthStateDidChangeListenerHandle?
    
      func registerAuthStateHandler() {
        if authStateHandler == nil {
          authStateHandler = Auth.auth().addStateDidChangeListener { auth, user in
            self.user = user
            self.authenticationState = user == nil ? .unauthenticated : .authenticated
            self.displayName = user?.email ?? ""
          }
        }
      }
    
    }
    
    // MARK: - Email and Password Authentication
    extension AuthenticationViewModel {
      func signInWithEmailPassword() async -> Bool {
        authenticationState = .authenticating
        do {
          try await Auth.auth().signIn(withEmail: self.email, password: self.password)
          return true
        }
        catch  {
          print(error)
          errorMessage = error.localizedDescription
          authenticationState = .unauthenticated
          return false
        }
      }
    
      func signUpWithEmailPassword() async -> Bool {
        authenticationState = .authenticating
        do  {
          try await Auth.auth().createUser(withEmail: email, password: password)
          return true
        }
        catch {
          print(error)
          errorMessage = error.localizedDescription
          authenticationState = .unauthenticated
          return false
        }
      }
    
      func signOut() {
        do {
          try Auth.auth().signOut()
        }
        catch {
          print(error)
          errorMessage = error.localizedDescription
        }
      }
    }
    

    The project also contains an AuthenticatedView, which will display a different view based on the authentication state:

    struct AuthenticatedView<Content, Unauthenticated>: View where Content: View, Unauthenticated: View {
      @StateObject private var viewModel = AuthenticationViewModel()
      @State private var presentingLoginScreen = false
      @State private var presentingProfileScreen = false
    
      var unauthenticated: Unauthenticated?
      @ViewBuilder var content: () -> Content
    
      public init(unauthenticated: Unauthenticated?, @ViewBuilder content: @escaping () -> Content) {
        self.unauthenticated = unauthenticated
        self.content = content
      }
    
      public init(@ViewBuilder unauthenticated: @escaping () -> Unauthenticated, @ViewBuilder content: @escaping () -> Content) {
        self.unauthenticated = unauthenticated()
        self.content = content
      }
    
    
      var body: some View {
        switch viewModel.authenticationState {
        case .unauthenticated, .authenticating:
          VStack {
            if let unauthenticated {
              unauthenticated
            }
            else {
              Text("You're not logged in.")
            }
            Button("Tap here to log in") {
              viewModel.reset()
              presentingLoginScreen.toggle()
            }
          }
          .sheet(isPresented: $presentingLoginScreen) {
            AuthenticationView()
              .environmentObject(viewModel)
          }
        case .authenticated:
          VStack {
            content()
            Text("You're logged in as (viewModel.displayName).")
            Button("Tap here to view your profile") {
              presentingProfileScreen.toggle()
            }
          }
          .sheet(isPresented: $presentingProfileScreen) {
            NavigationView {
              UserProfileView()
                .environmentObject(viewModel)
            }
          }
        }
      }
    }
    

    The docs show how to do this for Swift and Objective-C, and if you’d like to see how to implement this, check out one of my videos for Firebase Auth, in which I show how to implement this in SwiftUI:

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search