Firebase User Auth check in App delegate - ios

I have implemented Firebase Auth and Firebase Database in app delegate which checks if the user is logged in or not.It checks in a 'users' node in Database to see if there is an userid in child snapshots or not and this operation takes about 2-3 seconds.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
if let uid = Auth.auth().currentUser?.uid {
Database.database().reference().child("users").child(uid).observeSingleEvent(of: .value, with: { snapshot in
if snapshot.exists() {
print("App Delegate: User found!")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "Main")
self.window?.rootViewController = vc
self.window?.makeKeyAndVisible()
}
else{
print("App Delegate: User not found!")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "Login")
self.window?.rootViewController = vc
self.window?.makeKeyAndVisible()
}
})
}
return true
}
The Login viewController is the Initial viewController. When launch screen fades out, the login viewController is show and if the user is logged in, the Main viewController is shown but in this case, there is a time interval of 2-3 secs for which the Login viewController is being shown.
I tried to implement NavigationController too but same problem.
So how can I not show Login viewController if the user is logged in and go straight to the Main viewController and manage that 2-3 time seconds of time interval effectively.

Keep track isLogin variable in local session make it true and false while login and logout successful. When the first login then checks your session variable isLogin. You can save the session in UserDefault or Keychain. This way you can avoid your issue.
Or you just need to check this way:
if FIRAuth.auth().currentUser != nil {
presentHome()
} else {
//User Not logged in
}
After that when you navigated to desire viewController do rest of the things there.

Related

how to check is user is log in in different view controllers in firebase

I am making an app where user can upload files on cloud and retrieve later, but I am stuck.
My question is how to check if user is logged in or not,
if login page should be my view controller and every time a user opens the app they have to login or is there some way we can skip this procedure?
I tried making home page an initial view controller and checking in view didload if there is any user or not using auth.auth().currentuser.uid but I don't feel good about using it please any help would be appreciated.
I am new to firebase
if Auth.auth().currentuser.uid != nil {
//success code
}
in AppDelegate in didFinishLaunchingWithOptions
if Auth.auth().currentUser?.uid != nil {
self.window?.rootViewController = UINavigationController.init(rootViewController: viewController1())
} else {
self.window?.rootViewController = UINavigationController.init(rootViewController: viewController2())
}
to check if user is logged in with firebase, you need to implement this in the didFinishLaunchingWithOptions in the appDelegate
if Auth.auth().currentUser != nil {
// the user is logged in, you can now redirect to another view controller
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "YourStoryboardVCName") as! YourViewController
self.window?.rootViewController = vc
}
I think the below code might help you.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
configureFirebase()
configureApplicationScreen()
return true
}
// To determine which screen will be displayed when application is launched
func configureApplicationScreen() {
guard let rootNav = window?.rootViewController as? UINavigationController else {
return
}
// Might need to change the code inside if let depending your requirement
if let _ = Auth.auth().currentUser, UserDefaults.isUserLoggedIn {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let sideMenuVC = storyboard.instantiateViewController(withIdentifier: "SideMenuController")
rootNav.navigationBar.isHidden = true
rootNav.addChild(sideMenuVC)
}
}
extension UserDefaults {
static var isUserLoggedIn: Bool {
get {
return UserDefaults.standard.bool(forKey: "IsUserLoggedIn")
}
set {
UserDefaults.standard.set(newValue, forKey: "IsUserLoggedIn")
UserDefaults.standard.synchronize()
}
}
}
Once user is logged in you need to save the status in your UserDefault like
"UserDefaults.isUserLoggedIn = true" and you need to check it when the application is launched in the AppDelegate class as stated above.

Why my createUser Method Trigger addStateDidChangeListener Method in appDelegate?

In app delegate, I write codes to decide whether the user will go straight to Main Tab Bar if the user has already sign in, otherwise the user will be sent to Welcome Screen VC when the app is launched.
here is the code in my App Delegate.
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
checkUserLogin()
// to track the user default info.plist location in the device (simulator) for checking purpose.
print("The Location of info.plist of User Default: \(NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last! as String)")
return true
}
}
extension AppDelegate {
// MARK: - HELPER METHODS
func checkUserLogin() {
// to check whether the user has already logged in or not
SVProgressHUD.show()
Auth.auth().addStateDidChangeListener { (auth, user) in
if user == nil {
SVProgressHUD.dismiss()
self.goToWelcomeVC()
} else {
SVProgressHUD.dismiss()
self.goToMainTabBar()
}
// if user is not nil then automatically go to maintab bar (initialVC is indeed main tab bar controller)
SVProgressHUD.dismiss()
}
}
func goToMainTabBar () {
print("XXXXXXXX")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let mainTabBar = storyboard.instantiateViewController(withIdentifier: "mainTabBar")
window?.rootViewController = mainTabBar
}
func goToWelcomeVC () {
let storyboard = UIStoryboard(name: "Welcome", bundle: nil)
let login = storyboard.instantiateViewController(withIdentifier: "WelcomeVC")
window?.rootViewController = login
}
}
I am trying to create registerVC, after the user fill the text field, and press the register button I try to create user by using Firebase Authentication, the code will be triggered when the user press sign up button in registerVC
Auth.auth().createUser(withEmail: email, password: password) { (user, error) in
// ...
}
when Auth.auth().createUser() is triggered, it is automatically triggered Auth.auth().addStateDidChangeListener() method in my app delegate, so it makes my app automatically go to Main Tab Bar, at this point I want my app still in RegistrationVC, since the user have to verified their email first and then login to go to Main Tab Bar.
how to prevent the user to go to MainTab Bar when the Auth.auth().createUser(withEmail: email, password: password) is triggered? but I also want to keep the functionality the user will go straight to Main Tab Bar if the user has already sign in, otherwise the user will be sent to Welcome Screen VC when the app is launched. ?
You might resolved your problem by now, but this answer is for record.
I faced the same problem, and I solved it like this:
1 - Replace the inside of if user == nil { with:
let registeration = UserDefaults.standard.bool(forKey: "registering")
if(!registeration) {
SVProgressHUD.dismiss()
self.goToWelcomeVC()
}
2 - Above Auth.auth().createUser(withEmail: email, password: password) { (user, error) in line, add:
UserDefaults.standard.set(true, forKey: "registering")
3 - In your mainTabBar VC, inside viewDidLoad func, add this:
UserDefaults.standard.set(false, forKey: "registering")

AddingViewcontroller manually into the stack swift 3

I am coding the sign out button in my app.This is the flow of my app.
SplashvwController -> secretCodeViewController ->
LoginviewController -> DashboardViewController
in this DashboardViewController I have the signOut button.
My app has single sign in facility once user logged, next time when he opens the app,
SplashvwController -> DashboardViewController
I want to prompt the user to Loginviewcontroller whenever he clicks the sign out button.
Question
When user going through path 1 I can simply do popviewcontroller to go back to the previous viewcontroller. But when user go though the 2nd path,
how can I add the Loginviewcontroller manually into my
viewcontrollers stack to perform the same operation?
How can I check whether the LoginviewController exists in my current Viewcontrollers stack?
Please help me
I think, the below code helps you,
for (var i = 0; i < self.navigationController?.viewControllers.count; i++) {
if(self.navigationController?.viewControllers[i].isKindOfClass(Loginviewcontroller) == true) {
self.navigationController?.popToViewController(self.navigationController!.viewControllers[i], animated: true)
break;
}
}
To add a ViewController Manually , check the code below..
let navigation = mainStoryboard.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
let nav = UINavigationController(rootViewController: navigation)
appdelegate.window!.rootViewController = nav
Set the storyboard reference identifier for a LoginViewController on the Main.Storyboard file.
Whenever you want to show the LoginViewController just call the function
func launchLoginView() {
if let loginVC: LoginViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("LoginStoryboardID") as? LoginViewController {
// .instantiatViewControllerWithIdentifier() returns AnyObject! this must be downcast to utilize it
// LoginStoryboardID is the reference id for login view controller.
self.presentViewController(loginVC, animated: true, completion: nil).
// OR
//UIApplication.shared.keyWindow?.rootViewController = loginVC
}
}
Landing screen based on the User login status.
In AppDelegte.swift
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let isLoggedAlready = //Get the login status
if isLoggedAlready == true {
if let dashBoardVC: DashboardViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("DashboardStoryboardID") as? DashboardViewController {
//Already logged in then directly launch dashboard vc.
//change the code based on your needs
window?.rootViewController = dasbBoardVC
}
}
// Otherwise let it go as flow 1
return true
}
}

Can I retrieve data from NSUserDefaults after app termination?

I was wondering where NSUserDefaults is writing all the stored data to: to the app memory or to the device the app is running on? In the latter case, I guess I should be able to retrieve stored data from NSUserDefaults even if the app has been completely shut down, right? Basically what I'm trying to do: at runtime I want to check whether or not the user was logged in when he/she shut down the app (which I store in NSUserDefaults as a Boolean at the moment a user logs in or logs out), and if the user was logged in, I want to set a different root view controller from the original root view controller a user would see if the app was opened for the first time. I've tried a lot of different things, but nothing seems to work when I test it on my device. Is NSUserDefaults the best approach to do this (if so, then how?) or are there better alternatives to do this?
When using 'NSUserDefaults' for something simple like this it will work well for what you are trying to achieve.
This is the code you would place in your AppDelegate that will handle sending the user to the correct view based on the value.
Swift 2
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let logonStatus = NSUserDefaults.boolForKey("LogonStatus")
if logonStatus {
print("User logged in.")
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewControllerWithIdentifier("navController") as! UINavigationController
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
} else {
print("User not Logged in.")
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewControllerWithIdentifier("loginViewController") as UIViewController
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
}
return true
}
Then in your logout or logon viewController or the code to perform the logout or logon you would just need to make sure to set the 'NSUsersDefaults' value.
NSUserDefaults.setBool(true, forKey: "logonStatus") // Logged On
NSUserDefaults.setBool(false, forKey: "logonStatus") // Logged Off
Swift 3
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let logonStatus = UserDefaults.standard.bool(forKey: "LogonStatus")
if logonStatus {
print("User logged in.")
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "navController") as! UINavigationController
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
} else {
print("User not Logged in.")
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "loginViewController") as UIViewController
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
}
return true
}
Set 'UserDefaults'
UserDefaults.standard.set(true, forKey: "LogonStatus")
You've got a few questions here. NSUserDefaults is persistent across app launches, per this other answer on StackOverflow: Data persistence through NSUserDefaults. However, once you delete the app, you will lose the data.
In terms of programming for a root view controller, I would say yeah, if you want to show the login root view controller, that's a pretty strong case for storing login persistence in NSUserDefaults. Just don't store their login directly in the defaults of course :)
One thing I would note is that it quickly gets hard to reason about view hierarchy and you can introduce pretty nasty bugs if the root view controller is changing. Like, once the user logs in, what do you do with the old root view controller? Instead of what you describe, I'd keep the same root view controller, but present a modal for login over the top of the root if a login is needed. Simpler logic and your app will be more stable.

Check for user in session in AppDelegate and trigger UIViewController if not

I have a Swift application, and what I'd like to do is that every time the app becomes active, I'd like to check for a user in session. If not found, I'd like to show a login view controller that I designed in my Storyboard. If found, I need everything to just resume as usual.
Where is the best way to trigger this check? Is AppDelegate's applicationDidBecomeActive the right place for this?
If yes, how do I actually instantiate the login view controller and show it? I have another home view controller, which is set to be my initial view controller. How do I manage this controller if and when I do end up successfully pushing the login view controller from the app delegate in case there is no user found in session? I don't want the home view controller to show up if a user is not found.
Any advise is greatly appreciated!
Hope this answer can help!
Put this in your AppDelegate.swift file. With the if you can check the value saved in local memory.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
var userLoggedIn: Bool = NSUserDefaults.standardUserDefaults().boolForKey("isUserLoggedIn")
if (userLoggedIn){
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var homeViewController = mainStoryboard.instantiateViewControllerWithIdentifier("HomeViewController") as!
HomeViewController
window!.rootViewController = homeViewController
}
return true
}
If let's say you store a token in your usersession, we go look if there is a token set or not. If it's already set (so not null) then we go to your other viewcontroller
let prefs = NSUserDefaults.standardUserDefaults()
let checkfortoken = prefs.stringForKey("token")
if(checkfortoken != ""){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("identifierofyourview") as UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}
Now you want to check this when you start your app so we gonna put the code into appdelegate in the first function (didFinishLaunchingWithOptions):
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: true)
//so here ...
return true
}

Resources