Google didSignInForUser doesn't fire in swift 3 - ios

I am doing Google sign in in my project. I installed the SDK using CocoaPods. I have this same app written in Objective-C before. So I dragged the same Google configuration file (GoogleService-Info.plist) from my old project.
And I followed this with CocoaPods installed method. But when I press the sign in button I am directing to the Google web page and after I enter user name password it returns to my app. But this delegate doesn't trigger.
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError!) {
if error == nil {
// Perform any operations on signed in user here.
let userId = user.userID // For client-side use only!
let idToken = user.authentication.idToken // Safe to send to the server
let fullName = user.profile.name
let givenName = user.profile.givenName
let familyName = user.profile.familyName
let email = user.profile.email
let dm = Datamanager.sharedInstance
dm.gplusEmail = email
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "RETURNED_GOOGLE"), object: nil)
// ...
} else {
print("\(error.localizedDescription)")
}
}
My sign in button is a UIButton and in my ViewController I have implemented in this way:
#IBAction func googleClick(_ sender: UIButton) {
strLoggedWay="google"
GIDSignIn.sharedInstance().signIn()
}
Please help me. What's wrong with the process my code?

//In your login view controller
#IBAction func googleClick(_ sender: UIButton) {
strLoggedWay="google"
GIDSignIn.sharedInstance().clientID = //getGoogleClientId
GIDSignIn.sharedInstance().serverClientID = //getGoogleServerClientId
GIDSignIn.sharedInstance().uiDelegate = self
GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().scopes = #["https://www.googleapis.com/auth/userinfo.profile","https://www.googleapis.com/auth/userinfo.email"]
GIDSignIn.sharedInstance().signIn()
}
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!,
withError error: NSError!) {
if (error == nil) {
// Perform any operations on signed in user here.
let userId = user.userID // For client-side use only!
let idToken = user.authentication.idToken // Safe to send to the server
let fullName = user.profile.name
let givenName = user.profile.givenName
let familyName = user.profile.familyName
let email = user.profile.email
let dm=Datamanager.sharedInstance
dm.gplusEmail=email
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "RETURNED_GOOGLE"), object: nil)
// ...
} else {
print("\(error.localizedDescription)")
}
}

Related

How to convert Google iOS Sign-In single page sample AppDelegate.h protocol -> to a segue to LoginPage ViewController AppDelegate.swift protocol?

Google's Sign-In sample on GitHub SignInSampleForPod.xcworkspace creates a single page sign-in using the AppDelegate.h SignInViewController.m etc protocol.
However many apps, such as mine, prefer to segue to a Login Page only when a user makes a choice requiring verification. I just want the basic Google Profile info and authentication token.
I have the Google iOS ClientID configured enough so a segue to my LoginPage.swift shows the Google Sign-In button via AppDelegate.swift:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(
_ app: UIApplication,
open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]
) -> Bool {
var handled: Bool
handled = GIDSignIn.sharedInstance.handle(url)
if handled {
return true
}
// Handle other custom URL types.
// If not handled by this app, return false.
return false
}
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in
if error != nil || user == nil {
// Show the app's signed-out state.
} else {
// Show the app's signed-in state.
}
}
return true
}
And LoginPage.swift:
class LoginViewController: UIViewController {
let signInConfig = GIDConfiguration.init(clientID: "foo-bar85.apps.googleusercontent.com")
override func viewDidLoad() {
super.viewDidLoad()
GIDSignIn.sharedInstance.signIn(with: signInConfig, presenting: self) { user, error in
guard error == nil else { return }
guard let user = user else { return }
let emailAddress = user.profile?.email
let fullName = user.profile?.name
let givenName = user.profile?.givenName
let familyName = user.profile?.familyName
let profilePicUrl = user.profile?.imageURL(withDimension: 320)
}
So my question is what is the AppDelegate.swift Google Sign-In code for the fields shown below to display the basic profile info:
// Show the app's signed-out state.
} else {
// Show the app's signed-in state.
I may not able to understand your problem clearly.
But I am trying to answer based on my understanding.
You can create a class (GoogleLoginManager) for all google login related stuff and create a button in UI then call this method (signIn) from button action.
#IBAction func googleButtonAction(_ sender: Any) {
GoogleLoginManager.shared.signIn(controller: self) { (profile) in
print("GoogleLogin profile : \(String(describing: profile.name)), \(String(describing: profile.email))")
} onFailure: { (error) in
print("GoogleLogin error : \(String(describing: error.localizedDescription))")
}
}
import Foundation
import GoogleSignIn
class GoogleLoginManager: SocialLogin {
fileprivate var onSuccess : success?
fileprivate var onFailure : failure?
static let shared = GoogleLoginManager()
private override init() { }
func signIn(controller: UIViewController, onSuccess : #escaping success, onFailure : #escaping failure) {
self.onSuccess = onSuccess
self.onFailure = onFailure
GIDSignIn.sharedInstance().clientID = GOOGLE_CLIENT_ID
GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().presentingViewController = controller
GIDSignIn.sharedInstance().signIn()
// Automatically sign in the user.
// GIDSignIn.sharedInstance()?.restorePreviousSignIn()
}
func signOut() {
GIDSignIn.sharedInstance().signOut()
}
}
extension GoogleLoginManager : GIDSignInDelegate {
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!,
withError error: Error!) {
if let error = error {
if (error as NSError).code == GIDSignInErrorCode.hasNoAuthInKeychain.rawValue {
print("The user has not signed in before or they have since signed out.")
}
else if (error as NSError).code == GIDSignInErrorCode.canceled.rawValue {
print("user canceled the sign in request")
}
else {
print("\(error.localizedDescription)")
}
self.onFailure?(error)
return
}
var profile = SocialProfileModel.init(user: user)
profile.loginSuccess = true
self.onSuccess?(profile)
}
func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!,
withError error: Error!) {
// Perform any operations when the user disconnects from app here.
print("GIDSignIn : didDisconnectWith")
}
}
I just had to modify my above AppDelegate.swift slightly - adding a standard UIbutton linked to the following action - gets the profile info:
#IBAction func LogInButtonTouched(_ sender: UIButton) {
GIDSignIn.sharedInstance.signIn(with: signInConfig, presenting: self) { user, error in
guard error == nil else { return }
guard let user = user else { return }
let emailAddress = user.profile?.email
let fullName = user.profile?.name
let givenName = user.profile?.givenName
let familyName = user.profile?.familyName
let profilePicUrl = user.profile?.imageURL(withDimension: 320)
print("GoogleLogin profile : \(String(describing: user.profile?.name)), \(String(describing: user.profile?.email))")
}
}

swift firebase google sign in not showing on console

I am trying to sign in to firestore auth using the following GoogleSignInViewController but it shows nothing on the firebase console -
import UIKit
import Firebase
import GoogleSignIn
class GoogleSignInViewController: UIViewController {
var googleSignIn = GIDSignIn.sharedInstance()
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
#IBAction func googleLoginBtnAction(_ sender: UIButton) {
print("sign in tapped")
self.googleAuthLogin()
}
func googleAuthLogin() {
self.googleSignIn?.presentingViewController = self
self.googleSignIn?.clientID = "419387986978-pbs8h2drcjk60svqf1d5mgj0pa436r7b.apps.googleusercontent.com"
self.googleSignIn?.delegate = self
self.googleSignIn?.signIn()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "detailseg" {
let DestView = segue.destination as! DetailsViewController
}
}
}
extension GoogleSignInViewController: GIDSignInDelegate {
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
guard let user = user else {
print("Uh oh. The user cancelled the Google login.")
return
}
let userId = user.userID ?? ""
print("Google User ID: \(userId)")
let userIdToken = user.authentication.idToken ?? ""
print("Google ID Token: \(userIdToken)")
let userFirstName = user.profile.givenName ?? ""
print("Google User First Name: \(userFirstName)")
let userLastName = user.profile.familyName ?? ""
print("Google User Last Name: \(userLastName)")
let userEmail = user.profile.email ?? ""
print("Google User Email: \(userEmail)")
let googleProfilePicURL = user.profile.imageURL(withDimension: 150)?.absoluteString ?? ""
print("Google Profile Avatar URL: \(googleProfilePicURL)")
}
func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
}
}
It shows the login page as follows ( only for demonstrational purpose) -
Then, my app (Fireupgoodsa) takes permission from google to sign in -
Then, google takes permissioin to share my email id. information with the project -
Then, it goes to the DetailViewController (shown in red color below)-
Also, it shows alert message in my official email id.that my account was signed in to a new device i.e. my iOS simulator, which proves that sign in HAS taken place.
So far, so good -
but there is nothing on the firebase console -
This also didn't help me - Not getting the email using Google Authentication in Firebase
I had asked a similar bounty question - How to signoutout user from firebase console in swift
The bounty lapsed, but the problem was not sorted.
I have also deleted the project and created a new project. The screenshot of the project overview is shown below -
Now, why does not it show anything on the Firebase console. Is it something with the settings, project name. Do I need to add a tag container or something ? (Also, please see the address bar in the image above to see if something is wrong). What am I missing out on ?
This has been bugging me for quite a while.
I am desperate for help.
Please give me a hand with this, will you ?
I am posting the complete code for "class GoogleSignInViewController" and "class AppDelegate"-
class GoogleSignInViewController:-
import UIKit
import Firebase
import GoogleSignIn
class GoogleSignInViewController: UIViewController {
var googleSignIn = GIDSignIn.sharedInstance()
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
#IBAction func googleLoginBtnAction(_ sender: UIButton) {
print("sign in tapped")
self.googleAuthLogin()
}
#IBAction func googleLogoutBtnAction(_ sender: Any) {
let firebaseAuth = Auth.auth()
do {
try firebaseAuth.signOut()
print ("user is signed out")
} catch let signOutError as NSError {
print ("Error signing out: %#", signOutError)
}
}
func googleAuthLogin() {
self.googleSignIn?.presentingViewController = self
self.googleSignIn?.clientID = "9727299xxxxx-m0brc61v3a32br7b34pdjxxxxxxxxxxx.apps.googleusercontent.com"
self.googleSignIn?.delegate = self
self.googleSignIn?.signIn()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "detailseg" {
let DestView = segue.destination as! DetailsViewController
}
}
}
extension GoogleSignInViewController: GIDSignInDelegate {
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!){
if let err = error {
print ("failed to log into Google", err)
return
}
print("successfully logged into Google",user)
guard let idToken = user.authentication.idToken else {return}
guard let accessToken = user.authentication.accessToken else {return}
let credentials = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: accessToken)
Auth.auth().signInAndRetrieveData(with: credentials, completion: { (user, error) in
if let err = error {
print ("failed to create with google account", err)
return
}
print("successfuly logged into Firebase with Google", user?.user.uid)
})
}
func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
}
}
class AppDelegate:-
import UIKit
import GoogleSignIn
import Firebase
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
// Override point for customization after application launch.
GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
GIDSignIn.sharedInstance().delegate = self
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return GIDSignIn.sharedInstance().handle(url as URL?)
}
func sign(_ signIn: GIDSignIn!,
didSignInFor user: GIDGoogleUser!,
withError error: Error!) {
// Check for sign in error
if let error = error {
if (error as NSError).code == GIDSignInErrorCode.hasNoAuthInKeychain.rawValue {
print("The user has not signed in before or they have since signed out.")
} else {
print("\(error.localizedDescription)")
}
return
}
// Get credential object using Google ID token and Google access token
guard let authentication = user.authentication else {
return
}
let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
accessToken: authentication.accessToken)
// Authenticate with Firebase using the credential object
Auth.auth().signIn(with: credential) { (authResult, error) in
if let error = error {
print("Error occurs when authenticate with Firebase: \(error.localizedDescription)")
}
// Post notification after user successfully sign in
// NotificationCenter.default.post(name: .signInGoogleCompleted, object: nil)
}
}
func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
// Perform any operations when the user disconnects from app here.
print("User has disconnected")
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
The above codes works for me and show me signed in FirebaseAuth with my gmail id.:-
Note -This answer shows just how the user google/gmail sign-in on the FirebaseAuth console(which is what this question is all about) . I have not posted the code to show details in the DetailsiewController. I will post that code later when I have designed that.
Furthermore, If you want to write your Firebase Auth User UID to Firestore Document ID you can refer to the "class UserIdtoFirestoreViewController" of the question in the link:-
How to Show Firebase Auth User UID and also my Firestore doc uid as Stripe customer id

How does Google OAuth2.0 callback works in iOS app?

I wanna know how an iOS app grabs authorization grant after being called back from Safari after authorization with Google when using GoogleSignIn package.
I followed instructions on google's developer site that tells me to add following code to AppDelegate, which I believe is responsible for handling that.
func application(application: UIApplication,
openURL url: NSURL, options: [String: AnyObject]) -> Bool {
return GIDSignIn.sharedInstance().handleURL(url,
sourceApplication: options[UIApplicationOpenURLOptionsSourceApplicationKey] as? String,
annotation: options[UIApplicationOpenURLOptionsAnnotationKey])
}
But when I placed a breakpoint to this method, so I could see the url, it was never called. I even tried to delete this method and it still works!
Can somebody explain to me what kind of magic is that?
I have implemented Google Login in one of my application in following way...
Required pod
pod 'GoogleSignIn'
User Tap On Google Login Button
I've created custom button.
#IBAction func btnGoogleSignInTapped(_ sender: UIButton) {
GIDSignIn.sharedInstance().clientID = kGoogleClientID
GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().uiDelegate = self
GIDSignIn.sharedInstance().signIn()
}
GIDSignInDelegate Implementation
extension MyVC: GIDSignInDelegate {
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if (error == nil) {
// Perform any operations on signed in user here.
let userId = user.userID // For client-side use only!
let idToken = user.authentication.idToken // Safe to send to the server
let fullName = user.profile.name
let givenName = user.profile.givenName
let familyName = user.profile.familyName
let email = user.profile.email
debugPrint("user id = \(String(describing: userId))")
debugPrint("idToken = \(String(describing: idToken))")
debugPrint("fullName = \(String(describing: fullName))")
debugPrint("givenName = \(String(describing: givenName))")
debugPrint("familyName = \(String(describing: familyName))")
debugPrint("email = \(String(describing: email))")
//sign in successfull......
} else {
debugPrint("Google sign in error :\(error.localizedDescription)")
}
}
//-----------------------------------------------------
func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
debugPrint("User did disconnecte with error !!")
}
//-----------------------------------------------------
}
you need to set URL Type under info.plist file of your project...

Firebase google auth (swift)

Following the firebase docs i added the authentication with google account and this is part of the code that i have in my app delegate
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) {
if let error = error {
print("Failed to log into Google: ", error)
return
}
print("Successfully logged into Google", user)
guard let idToken = user.authentication.idToken else { return }
guard let accessToken = user.authentication.accessToken else { return }
let credentials = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: accessToken)
Auth.auth().signIn(with: credentials, completion: { (user, error) in
if let err = error {
print("Failed to create a Firebase User with Google account: ", err)
return
}
guard let uid = user?.uid else { return }
print("Successfully logged into Firebase with Google", uid)
})
}
func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
// Perform any operations when the user disconnects from app here.
// ...
}
but the google button
fileprivate func setupGoogleButtons() {
googleButton.frame = CGRect(x: 189, y: 532, width: 118, height: 41)
view.addSubview(googleButton)
GIDSignIn.sharedInstance().uiDelegate = self
}
is obviously in a viewController, what i would like to do is an automatically self.performSegue(withIdentifier: "goToHome1", sender: self) as soon as the user logs in with his google account, because at the moment after login the user always finds on the same VC. How can i do this?
UPDATE
I solve my problem following this question Google and Facebook Firebase Auth using swift 3
If there is no error then the user signed in successfully so you should segue. The button itself just calls the sign in function. Depending on whether the sign in fails or succeeds you alert or segue.
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) {
if let error = error {
print("Failed to log into Google: ", error)
return
}
print("Successfully logged into Google", user)
guard let idToken = user.authentication.idToken else { return }
guard let accessToken = user.authentication.accessToken else { return }
let credentials = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: accessToken)
Auth.auth().signIn(with: credentials, completion: { (user, error) in
if let err = error {
print("Failed to create a Firebase User with Google account: ", err)
return
}
guard let uid = user?.uid else { return }
print("Successfully logged into Firebase with Google", uid)
// segue here
DispatchQueue.main.async {
self.performSegue(withIdentifier: "goToHome1", sender: self)
}
})
}
The Auth class has a function addAuthStateDidChangeListener:, check it here.
It will trigger any time the user changes, particularly when the user logs in, the callback will return a non-nil user. That's the time you want to perform the segue.

how do I perform segue after log in with google account?

I've been working on sign in with Google account.
I basically followed the guide from Friebase (https://firebase.google.com/docs/auth/ios/google-signin)
It worked, but I have trouble performing segue to my main page from sign in page
here's the code in my signin View controller :
class SignInController: UIViewController, GIDSignInUIDelegate{
#IBOutlet weak var signInButton: GIDSignInButton!
override func viewDidLoad() {
super.viewDidLoad()
GIDSignIn.sharedInstance().uiDelegate = self
GIDSignIn.sharedInstance().signInSilently()
}
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError!) {
if let err = error {
print(error)
}
else {
performSegue(withIdentifier: "GoToMain", sender: self)
}
}
it should work if i put performSegue in the signIn function but it didn't
after log in with google successfully, it goes back to protected (sign in) page
I've been working and trying to shoot this problem for almost 6 hours, still can't figure it out !!!
self learning is a lot of pain.
any help is appreciated!!!
Thanks!!
Ian.
update
so now my code is like the following :
class SignInController: UIViewController, GIDSignInUIDelegate, GIDSignInDelegate {
#IBOutlet weak var signInButton: GIDSignInButton!
override func viewDidLoad() {
super.viewDidLoad()
GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().uiDelegate = self
GIDSignIn.sharedInstance().signInSilently()
GIDSignIn.sharedInstance().clientID = FIRApp.defaultApp()?.options.clientID
}
public func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if let authentication = user.authentication
{
let credential = FIRGoogleAuthProvider.credential(withIDToken: authentication.idToken, accessToken: authentication.accessToken)
FIRAuth.auth()?.signIn(with: credential, completion: { (user, error) -> Void in
if error != nil
{
print("Problem at signing in with google with error : \(error)")
}
else if error == nil{
print("user successfully signed in through GOOGLE! uid:\(FIRAuth.auth()!.currentUser!.uid)")
}
})
}
}
func signIn(signIn: GIDSignIn!, didDisconnectWithUser user: GIDGoogleUser!, withError error: NSError!) {
}
I added GIDsignDeligate protocol otherwise there will be an error at line
"GIDSignIn.sharedInstance().delegate = self"
When I run it, it crashed with "unexpectedly found nil while unwrapping an Optional value error" (seem to happen at "if let authentication = user.authentication"
)
Am i missing anything?
I feel I'm almost there!
Just add GIDSignIn.sharedInstance().delegate = self to your viewDidLoad function:-
override func viewDidLoad() {
super.viewDidLoad()
GIDSignIn.sharedInstance().uiDelegate = self
GIDSignIn.sharedInstance().signInSilently()
GIDSignIn.sharedInstance().clientID = FIRApp.defaultApp()!.options.clientID
GIDSignIn.sharedInstance().delegate = self
}
And change your sign in user function to:-
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError!) {
if let authentication = user.authentication
{
let credential = FIRGoogleAuthProvider.credential(withIDToken: authentication.idToken, accessToken: authentication.accessToken)
FIRAuth.auth()?.signIn(with: credential, completion: { (user, error) -> Void in
if error != nil
{
print("Problem at signing in with google with error : \(error)")
}
else if error == nil{
print("user successfully signed in through GOOGLE! uid:\(FIRAuth.auth()!.currentUser!.uid)")
}
})
}
}
PS:- This is swift3 version, so don't just copy paste it. Try writing it and autoComplete will help.

Resources