Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I implemented a google sign in in ios app. Now, how can I verify if user is logged in and if not - return him to the login page with Swift?

As I wrote in the title of this question - I went through this tutorial https://developers.google.com/identity/sign-in/ios/sign-in and now I'm able to log in the user to my app based on his google credentials.

The way I do it so far is that I have a ViewController.swift class with the following code:

class ViewController: UIViewController, GIDSignInUIDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        let background = CAGradientLayer().greenBlue()
        background.frame = self.view.bounds
        self.view.layer.insertSublayer(background, atIndex: 0)
        //GIDSignIn.sharedInstance().uiDelegate = self

        // Uncomment to automatically sign in the user.
        //GIDSignIn.sharedInstance().signInSilently()

    }

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        GIDSignIn.sharedInstance().uiDelegate = self

        GIDSignIn.sharedInstance().signInSilently()
    }

    @IBAction func didTapSignOut(sender: AnyObject) {
        GIDSignIn.sharedInstance().signOut()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func signInWillDispatch(signIn: GIDSignIn!, error: NSError!) {
        print("Nothing!")
    }

    // Present a view that prompts the user to sign in with Google
    func signIn(signIn: GIDSignIn!,
        presentViewController viewController: UIViewController!) {
            self.presentViewController(viewController, animated: true, completion: nil)
    }

    // Dismiss the "Sign in with Google" view
    func signIn(signIn: GIDSignIn!,
        dismissViewController viewController: UIViewController!) {
            self.dismissViewControllerAnimated(true, completion: nil)
    }
}

and in my AppDelegate.swift class I have:

class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {

    var window: UIWindow?


    func application(application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
            // Initialize sign-in
            var configureError: NSError?
            GGLContext.sharedInstance().configureWithError(&configureError)
            assert(configureError == nil, "Error configuring Google services: \(configureError)")

            GIDSignIn.sharedInstance().delegate = self

            return true
    }

    // [START openurl]
    func application(application: UIApplication,
        openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
            return GIDSignIn.sharedInstance().handleURL(url,
                sourceApplication: sourceApplication,
                annotation: annotation)
    }
    // [END openurl]

    @available(iOS 9.0, *)
    func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
        return GIDSignIn.sharedInstance().handleURL(url,
            sourceApplication: options[UIApplicationOpenURLOptionsSourceApplicationKey] as! String?,
            annotation: options[UIApplicationOpenURLOptionsAnnotationKey])
    }

    // [START signin_handler]
    func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!,
        withError error: NSError!) {
            if (error == nil) {
                print("Signed in!")
            } else {
                print("\(error.localizedDescription)")

            }
    }
    // [END signin_handler]

    // [START disconnect_handler]
    func signIn(signIn: GIDSignIn!, didDisconnectWithUser user:GIDGoogleUser!,
        withError error: NSError!) {
            // Perform any operations when the user disconnects from app here.
            // [START_EXCLUDE]
            NSNotificationCenter.defaultCenter().postNotificationName(
                "ToggleAuthUINotification",
                object: nil,
                userInfo: ["statusText": "User has disconnected."])
            // [END_EXCLUDE]
    }
}

My storyboard looks as follows:

enter image description here

On the left I have a ViewController with marked google button (which is white, therefore it's not visible here - sorry!) and on the right I have a main TabController view that contains the whole logic of my app (so far it's quite empty):

class TabController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let background = CAGradientLayer().greenBlue()
        background.frame = self.view.bounds
        self.view.layer.insertSublayer(background, atIndex: 0)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

Now it works like this:

I run the app and see the google button to sign in. I sign in and when everything is validated - nothing changes, I'm not moving to the second screen (TabController). I just stay on this view and I can keep clicking the google button - nothing changes though because I'm already signed in.

I want to achieve a situation when the user opens my app and when he is not logged in - he sees the ViewController screen. When he logs in - he sees the TabController screen. And also when he already signed in before and opens my app - he immediately jumps to TabController and skips the ViewController page. How can I achieve it?

I suspect I have to mark on my storyboard my TabController to be the initial view controller, but what about the log in screen?

=====EDIT

following Mac Bellingrath answer I modified my function in appDelegate.swift class, now it looks like this:

func application(application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Initialize sign-in
        var configureError: NSError?
        GGLContext.sharedInstance().configureWithError(&configureError)
        assert(configureError == nil, "Error configuring Google services: \(configureError)")

        GIDSignIn.sharedInstance().delegate = self

        /* check for user's token */
        if GIDSignIn.sharedInstance().hasAuthInKeychain() {
            /* Code to show your tab bar controller */
            print("user is signed in")
            let sb = UIStoryboard(name: "Main", bundle: nil)
            if let tabBarVC = sb.instantiateViewControllerWithIdentifier("TabController") as? UITabBarController {
                window!.rootViewController = tabBarVC
            }
        } else {
            print("user is NOT signed in")
            /* code to show your login VC */
            let sb = UIStoryboard(name: "Main", bundle: nil)
            if let tabBarVC = sb.instantiateViewControllerWithIdentifier("ViewController") as? ViewController {
                window!.rootViewController = tabBarVC
            }
        }

        return true
}

Now when I run the app and the user has been signed in before - I see the tabController view. If he wasn't signed in before - I see the ViewController view. It works almost like a charm, but I realized that no matter if I write if GIDSignIn.sharedInstance().hasAuthInKeychain() { or if !GIDSignIn.sharedInstance().hasAuthInKeychain() { it always prints out the message user is signed in, so something is still not right...

like image 400
randomuser1 Avatar asked Feb 13 '16 13:02

randomuser1


People also ask

How do I find my reverse client ID?

Open your project configuration: double-click the project name in the left tree view. Select your app from the TARGETS section, then select the Info tab, and expand the URL Types section. Click the + button, and add your reversed client ID as a URL scheme.

How do I log into Google firebase Swift?

If you haven't yet connected your app to your Firebase project, do so from the Firebase console. Enable Google as a sign-in method in the Firebase console: In the Firebase console, open the Auth section. On the Sign in method tab, enable the Google sign-in method and click Save.


3 Answers

Mac Bellingrath given perfect answer for verify user is logged in.

Alternate way to check user logged in.

Here is sample code in Objective-C you can convert code as per your requirement.

This sample code is just for your reference.

    // The authentication object for the current user, or |nil| if there is currently no logged in user.
    // Here you can get current user object
    GIDGoogleUser *googleUser = [[GIDSignIn sharedInstance] currentUser];

    if (googleUser) {
        // Get new token from google and send to server
        NSString *strToken = googleUser.authentication.idToken;
    }
    else {
        // present login screen here
        [self presentLoginScreen];
    }
like image 95
Vivek Avatar answered Oct 11 '22 16:10

Vivek


According to Google's documentation, it appears that you can use GIDSignIn's instance method hasAuthInKeychain() to check whether the user has either currently signed in or has previous authentication saved in keychain.

So, in your AppDelegate's

func application(application: UIApplication,didFinishLaunchingWithOptions                    launchOptions: [NSObject: AnyObject]?) -> Bool {

You might write something like:

GIDSignIn.sharedInstance().delegate = self
/* check for user's token */
if GIDSignIn.sharedInstance().hasAuthInKeychain() {
/* Code to show your tab bar controller */
} else {
/* code to show your login VC */
}

for example if our user is signed in:

let sb = UIStoryboard(name: "Main", bundle: nil)
if let tabBarVC = sb.instantiateViewControllerWithIdentifier("MainTabBarVC") as? UITabBarController {
window.rootViewController = tabBarVC
}

*Substitute your UITabBarController subclass for UITabBarController.

Of course, there are many ways to change the flow. Check out storyboard reference and multiple storyboards.

like image 36
Mac Bellingrath Avatar answered Oct 11 '22 16:10

Mac Bellingrath


let googleUser = GIDSignIn.sharedInstance().isCurrentUser

if googleUser != nil {
// Get new token from google and send to server
let strToken = googleUser.authentication.idToken
} else {
// present login screen here
presentLoginScreen()
}
like image 45
vamsi Avatar answered Oct 11 '22 17:10

vamsi