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:
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...
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.
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.
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];
}
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.
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()
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With