Prevent Login Screen from showing when auto login - ios

I have implemented the auto login within my app into the viewcontroller linked to the Login View Controller. However, given below, the storyboard navigates to the Login screen first after the launcher screen. When there are credentials found in the keystore, the app will auto login, but the Login screen will still flash before then moving on.
How can I ensure the login screen will not appear if the user credentials are already in the keystore and navigate directly to the Reveal View Controller?

Complement to the #Kerby Jean answer. First remove the entry point in the storyBoard, assign the point by code in your app delegate at didFinishLaunchingWithOptions method, something like this:
UIWindow * window
var storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
//Slect initial viewController
self.window = UIWindow(frame: UIScreen.mainScreen.bounds)
UIViewController * viewController
var preferences: NSUserDefaults = NSUserDefaults.standardUserDefaults()
var userId: String = preferences["userId"]
if userId != nil {
viewController = storyboard.instantiateViewControllerWithIdentifier("NavigationController")
}
else {
viewController = storyboard.instantiateViewControllerWithIdentifier("LoginViewController")
}
self.window.rootViewController = viewController
self.window.makeKeyAndVisible()

Store the user details in your loginScreen
NSUserDefaults.standardUserDefaults().setObject("\(userNameTxtField.text!)", forKey: "userName")
NSUserDefaults.standardUserDefaults().synchronize()
Put this function in your appDelegate
func userIsLoggedIn() {
let userName = NSUserDefaults.standardUserDefaults().stringForKey("userName")
if userName != nil {
//Navigate to Reveal View Controller
}
}
Then call the function in ViewDidFinishLauchingWithOption(In AppDelegate)
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
userIsLoggedIn()
return true
}

Related

Firebase User Auth check in App delegate

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.

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
}
}

Segue from LaunchScreen to a viewController in Main.Storyboard?

I got some logic I want to do in my LaunchScreen, and if the check is alright, I want to segue to a viewController and if not I want to segue to another, is that possible?
I got some logic I want to do in my LaunchScreen
Now that I understand the question, I can answer it: don't. Do your time-consuming logic later. Your job is to launch fast. You need to get out of applicationDidFinishLaunchingWithOptions, get out of viewDidLoad, and launch.
What you show at that point is up to you; if you have time-consuming stuff (in your case, it sounds like you're networking or doing something else that takes time while you load up the data source for a table) and you want to show a special view controller that covers the time with a spinning activity view or something, fine. But during actual launch is not the time to do that.
No you cant code for launchScreen.Storyboard, The reason why :- when your launchScreen.storyboard shows the app is still loading.
Simply put: You cant access your app when it is displaying launchScreen.storyboard, all you can do is make a UI/UX for that not execute any code for it.
Alternative:- Make a viewController that appears as a first viewController check your logic there and do things from there accordingly!
Reference : - https://stackoverflow.com/a/27642160/6297658
Your LaunchScreen is shown while your app is loading. Go to your AppDelgate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
window.rootViewController = //your root view controller that you have figured out with logic
return true
}
Run your check in didFinishLaunchingWithOptions() and use that to "jump" directly to a specific vc. Here's an example using userDefaults, but of course you can replace that with whatever check you're running.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Do some logic
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let welcomeVC = storyboard.instantiateViewControllerWithIdentifier("WelcomeNavController")
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.rootViewController = welcomeVC
self.window?.makeKeyAndVisible()
}
}
Add this function into the AppDelegate:
func initialVC(storyboardID: String) {
let mainStoryboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController : UIViewController = mainStoryboard.instantiateViewControllerWithIdentifier("\(storyboardID)") as UIViewController
self.window?.makeKeyAndVisible()
if storyboardID == "tabBarVC" {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.rootViewController = initialViewController
} else {
let navController = UINavigationController(rootViewController: initialViewController)
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.rootViewController = navController
}
}
In the didFinishLaunchingWithOptions method inside of the AppDelegate, you can add this:
if currentUser != nil {
initialVC("tabBarVC")
} else {
initialVC("loginVC")
}
You can see in my example, I am either loading the main app VC or the Login VC depending on if the user is logged in. In your case, You can use an if - else statement and do the logic within the initialVC function.
Note: When I call for the loginVC to be loaded, I have to load the navigationController because the loginVC is embedded in a navigationController. For the tabBarVC, I don't embed the navController because it isn't needed.

How to hide a Storyboard/ViewControllers forever?

I am working on an app that has two Storyboards: One for my app's onboarding controllers and the other for my main app. My onboarding view controller has a skip button that when pressed directs the user to the main storyboard. I only want to show the onboarding view as long as the user hasn't hit the skip button. Once the skip button is hit, the corresponding storyboard should disappear forever.
I thought I could fix this problem by only making showing onboarding storyboard when the app is first opened, and I found some code online that seemed helpful, however it doesn't work...here is the code that is in my app's AppDelegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
FIRApp.configure()
Fabric.with([Crashlytics.self])
let defaults = NSUserDefaults.standardUserDefaults()
if (defaults.objectForKey("userAsLoggedInBefore") != nil) {
print("Functions")
//here you insert the code to go to the main screen
var mainView: UIStoryboard!
mainView = UIStoryboard(name: "Functions", bundle: nil)
let viewcontroller : UIViewController = mainView.instantiateViewControllerWithIdentifier("functions") as UIViewController
self.window!.rootViewController = viewcontroller
} else {
//this means the user hasn't logged in before and you can redirect him to the onboarding page
print("Onboarding")
var mainView: UIStoryboard!
mainView = UIStoryboard(name: "Main", bundle: nil)
let viewcontroller : UIViewController = mainView.instantiateViewControllerWithIdentifier("onboarding") as UIViewController
self.window!.rootViewController = viewcontroller
}
}
Note in my code "Main" is the onboarding storyboard, while "Functions" is my main app code.
However this code is not working as intended as my same problem still arises. If anybody could take a look at my code and see if I am doing anything wrong, that would be greatly appreciated.
Thanks in advance!
You are never writing to NSUser defaults. So it will stay nil..
Your missing some line like this:
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setValue("Did watch", forKey: "userAsLoggedInBefore")
Put it at the end of if - else statement

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