I have an app which is connected to Firebase and you can login using Google and Facebook. The app has a home screen which is loaded when the user is signed in. I don't want to show the login screen if the user has already signed in before. So I use this code in the home screen to check if the user is signed in. Home screen is the initial view controller in the app
override func viewDidAppear(_ animated: Bool) {
if Auth.auth().currentUser != nil{
// user is signed in
}else{
// No user is signed in.
performSegue(withIdentifier: "login", sender: nil)
}
}
This code works very well. I know, that I could use UserDefaults too, but this seems to be an easier way. Is it wrong or should I use UserDefaults?
But the only problem with that is, for a quick moment the home screen is shown and then the segue is performed to the login screen, and I guess it's because it's in the viewdidApepar method, so the code gets executed after the viewcontroller appeared. Do you know a solution to it?
This is what I do personally, didFinishLaunchingWithOptions in AppDelegate.
if UserManager.sharedManager.currentUser != nil {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let viewController = storyboard.instantiateInitialViewController()
appDelegate.window?.rootViewController = viewController
} else {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let storyboard = UIStoryboard(name: "Login", bundle: Bundle.main)
let viewController = storyboard.instantiateInitialViewController()
appDelegate.window?.rootViewController = viewController
}
Of course I have a UserManager which handles if the user is logged in or not.(UserManager:NSObject)
var currentUser: User? {
return User.unarchiveStoredUser()
}
User is stored with decoder into UserDefautls then unarchived to verify if a user is logged in or not (User :NSObject)
func archiveUser() {
let data = NSKeyedArchiver.archivedData(withRootObject: self)
UserDefaults.standard.set(data, forKey: "userIdentifier")
UserDefaults.standard.synchronize()
}
class func unarchiveStoredUser() -> User? {
if let data = UserDefaults.standard.object(forKey: "userIdentifier") as? Data {
let user = NSKeyedUnarchiver.unarchiveObject(with: data) as! User
return user
}
return nil
}
Hope it helps you.
Related
I want to present one Storyboard after loading the App if the User is logged in and an other if the user have to log In.
I did it by overwriting the ViewWillAppear method, which now contains the code that is routed to the other storyboard when the user is logged in.
override func viewWillAppear(_ animated: Bool) {
let userdefaults = UserDefaults.standard
if userdefaults.string(forKey: "autoemail") != nil {
let email = userdefaults.string(forKey: "autoemail")
let password = userdefaults.string(forKey: "autopass")
Auth.auth().signIn(withEmail: email!, password: password!) { (user, error) in
self.performSegue(withIdentifier: "SignInSeguettt", sender: nil)
}
}
}override func viewWillAppear(_ animated: Bool) {
let userdefaults = UserDefaults.standard
if userdefaults.string(forKey: "autoemail") != nil {
let email = userdefaults.string(forKey: "autoemail")
let password = userdefaults.string(forKey: "autopass")
Auth.auth().signIn(withEmail: email!, password: password!) { (user, error) in
self.performSegue(withIdentifier: "SignInSeguettt", sender: nil)
}
}
}
But now the screen that would otherwise appear for a second still comes. How can I avoid that? I thought maybe by setting animated to false. I don't know how I can do this, because if I do it like that i get this Error:
Method does not override any method from its superclass
Are there other ways to get around this brief appearance of the wrong controller?
I don't think loading a view controller then making a decision whether to display it or load another view controller is the best approach to what you are trying to do.
The way I determine whether to allow the user to proceed into the app, or if they are not logged in display the login screen is done in the SceneDelegate.swift class (or could be done in the AppDelegate class if your app doesnt have a SceneDelegate)
It's done like this:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
override init() {
FirebaseApp.configure() // Configure Firebase
}
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
var vc: UIViewController // Create a viewcontroller ready to return as the viewcontroller we are going to show to the user
if (Auth.auth().currentUser) != nil { // The users' auth token is still good, they are logged in
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil) // get a storyboard reference
// Make our holding view controller an instance of the Main storyboard's initial view controller
vc = mainStoryboard.instantiateInitialViewController()!
} else { // the user is not logged in
// Has the user seen the onboarding screen before?
if Session.HasShownOnboarding { // Yes has seen the onboardinng screens
let mainStoryboard = UIStoryboard(name: "Account", bundle: nil) // get reference to the Account storyboard
// Make our holding view controller an instance of the Account storyboard's Log In view controller
vc = mainStoryboard.instantiateViewController(identifier: "LoginViewController")
} else { // No the user has not been shown the onboarding screens yet
let launchStoryboard = UIStoryboard(name: "Onboarding", bundle: nil) // get reference to the Onboarding storyboard
// Make our holding view controller an instance of the Onboading storyboard's Onboarding view controller
vc = launchStoryboard.instantiateViewController(identifier: "OnboardingViewController")
Session.HasShownOnboarding = true
}
}
// Make the app's default view controller to display, whatever we set from the logic above, either Main, or Login, or Onboarding
self.window?.rootViewController = vc
}
// ...
}
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.
I’m making an app, and I need to show only one time the on boarding view controller, so when the user re enter the app the on boarding view controller doesn’t appear any more.
I guess the on boarding view controller is your initial view controller. Try this in app delegate
First put checkFunction() in didFinishLaunchingWithOptions then set the identity (eg. Home) for the view controller you want to go
func checkFunction() {
let acceptedTerms = UserDefaults.standard.string(forKey: "acceptedTerms")
if acceptedTerms != nil && acceptedTerms == "Yes" {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let VC = storyBoard.instantiateViewController(withIdentifier: "Home")
self.window?.rootViewController = VC
}
}
Second, modify UserDefaults.standard.string in somewhere
// example
#IBAction func acceptButtonTapped(_ sender: AnyObject) {
UserDefaults.standard.set("Yes", forKey: "acceptedTerms")
UserDefaults.standard.synchronize()
}
I just finish a tutorial video of letsbuildthatapp about firebase mixed with social login.
I currently trying to perform a segue if the user is already authenticated.
I print something in my if and just after I performSegue with a segue who I know work because I'm using it for a test.
there is my code
func verifDejaConnecter() {
if Auth.auth().currentUser?.uid != nil {
performSegue(withIdentifier: "segueAccueilToPres", sender: nil)
print("test")
} else {
return
}
}
mySegue is created and works but nothing append here.
In the console I can see the test resulting from the print in the if ... but nothing is mooving
Try this:
func verifDejaConnecter() {
if Auth.auth().currentUser?.uid != nil {
DispatchQueue.main.async {
self.performSegue(withIdentifier: "segueAccueilToPres", sender: self)
print("test")
}
} else {
return
}
}
If you want to show a different controller when opening the app if the User is logged in, I would suggest you instantiate a different controller... Heres the code I'm using for this. (In AppDelegate)
if ((Auth.auth().currentUser) != nil)
{
initialViewController = mainStoryboard.instantiateViewController(withIdentifier: "tabBarController") as! UITabBarController // or UIViewController depending on your setup.
}
else
{
initialViewController = mainStoryboard.instantiateViewController(withIdentifier: "LoginController") as!
LoginController // or your login controller.
}
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
where "LoginController" & "tabBarController" you will need to input these into the storyBoard Identity inspector under Identity, StoryBoard Identity.
I'm an android developer. in android, when user login in application, I will re-open the MainActivity class ( controller ) to refresh some views.
in iOS applications, how to do this scenario ?
You can reopen you default/LandingViewController.
Suppose you have a View Controller with name LandingViewController
When you successfully logged in all you need is to re instantiate the LandingViewController
In AppDelegate class make a function with name
func userDidLoggedIn(){
let storyboard = UIStoryboard(name: "Main", bundle: nil)//Replace Main With your own storyboard name containing LandingViewController
let landingViewController = storyboard.instantiateViewController(withIdentifier: "LandingViewControllerIdentifier")//Pass your LandingViewController Identier that you have set in your storyboard file.
guard let subviews = self.window?.subviews else {
return
}
for view in subviews {
view.removeFromSuperview()
}
self.window?.rootViewController = landingViewController
}
Now Simply Call this Function where ever in the entire project like this In your case write below lines in the completion block of login request API.
let delegate = UIApplication.shared.delegate as! AppDelegate
delegate. userDidLoggedIn()
Once user login, you can change your rootviewcontroller like this:
var nav_VC: UIViewController?
func onSuccessfulLogin()
{
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
nav_VC = nil
if nav_VC == nil {
nav_VC = storyboard.instantiateViewController(withIdentifier: "home_nav")
}
self.window?.rootViewController = nav_VC
self.window?.makeKeyAndVisible()
}