iOS Firebase sign in. Show activity indicator after Google account choosing - ios

I have a ViewController with a Sign in button used to sign in into Firebase with a Google Account:
GIDSignIn.sharedInstance().signIn()
When I click the button, this appears:
Google account choosing
After selecting an account and if the authentication is successful, I want to load a second ViewController. For this, I have a listener in the first ViewController that will sign in again when the authentication state changes, this time successfully, without asking the account again and sending me directly to the second ViewController:
Auth.auth().addStateDidChangeListener({ auth, user in
if let _ = user {
GIDSignIn.sharedInstance().signIn()
}
})
The problem is that I want an activity indicator to be shown when I go back to the first ViewController from the account chooser. Because the app may be there for a few seconds during the authentication process and I don't want the user to tap again the Sign In button, while the first signing in hasn't already finished.
I need a way to recognise that a signing in process is taking place, to show an activity indicator that locks the screen to prevent the user from tapping again Sign in.
WORKAROUND 1
When I click the Sign in with Google button, I set an UserDefaults integer as 1. Then, when the ViewController is reloaded after the Google account chooser, I look for this integer and if it's 1, I don't stop the activity Indicator.
Because I want the activity indicator shown since the user clicks the button until the authentication is completed.
When button is clicked I do:
GIDSignIn.sharedInstance().signIn()
UserDefaults.standard.set(1, forKey: "signingIn")
UserDefaults.standard.synchronize()
In viewWillAppear I do:
if let _ = user {
GIDSignIn.sharedInstance().signIn()
} else {
if UserDefaults.standard.integer(forKey: "signingIn") != 1 {
self.stopActivityIndicator()
} else {
UserDefaults.standard.set(0, forKey: "signingIn")
UserDefaults.standard.synchronize()
}
}
When the authentication is completed, in GIDSignInDelegate there is the function that will be called. In this function, the activity indicator must be stopped:
// The sign-in flow has finished and was successful if |error| is |nil|.
- (void)signIn:(GIDSignIn *)signIn didSignInForUser:(GIDGoogleUser *)user withError:(NSError *)error;
WORKAROUND 2
I do a put the signIn Google function into a completion handler but it doesn't work:
self.completionHandlerSigIn {
self.stopActivityIndicator()
}
And the function is this:
func completionHandlerSigIn(completion: () -> Void) {
GIDSignIn.sharedInstance().signIn()
}
The problem is that the view is reloaded during the sign in process, after the account choosing. I need a way to recognize that I come from the Google Account choosing screen.

Just show the loading indicator right when the user clicks sign in, then hide it either when the authentication process returns with error or after processing the result. I don't use google sign in, but I can give you my example with Twitter.
#IBAction func onTwitterClicked(_ sender: UIButton) {
AuthManager.shared.loginWithTwitter(self)
}
Here is the loginWithTwitter method in AuthManager:
func loginWithTwitter(_ viewController:BaseController) {
self.provider = .twitter
viewController.showLoadingPanel()
TWTRTwitter.sharedInstance().logIn(completion: {session, error in
guard (error == nil) else {
viewController.hideLoadingPanel()
viewController.showInfoAlert("Oops", error!.localizedDescription, nil)
return
}
let credential = TwitterAuthProvider.credential(withToken: session!.authToken, secret: session!.authTokenSecret)
self.auth.signIn(with: credential, completion: {user, error in
viewController.hideLoadingPanel()
guard error == nil else {
viewController.showInfoAlert("Oops", error!.localizedDescription, nil)
return
}
self.tryConfirmUserInFirestore(user, viewController)
})
})
}

Related

MSAL signout - how to determine if the user selects 'cancel' [Swift]

I am currently using MSAL signout function in my iOS app and have no way of knowing if the user selects 'Continue' or 'Cancel'. Currently, once log out is completed the user is taken back to the root screen of the app. However, I need to be able to stop the flow so that if the user chooses to cancel, they are still on the same screen before choosing the log out option.
private func signout(with account: MSALAccount, signoutParameters: MSALSignoutParameters, completion: #escaping () -> Void) {
self.application.signout(with: account, signoutParameters: signoutParameters, completionBlock: { (result, error) in
if error != nil {
return
}
SharedStorage.authData = nil
completion()
})
}
The issue I have is that result returns true whether the user chooses continue or cancel and error returns nil. Curious if anyone has run into this issue before?

How to check whether the user is new user or old user

I have one login screen, which have email, password. And in register screen after user registred they will come to login screen to login.
That time I need to check , if the user is first time user or old user. If first time user means I need to redirect them to my feedback screen. Or old user means I need to redirect them to my home screen. How to do that with firebase?
Her my code for login screen :
#IBAction func loginWithUserNamePassword(){
loginWithMailAndPassword((username.text?.trimWhiteSpace)!, password: (password.text?.trimWhiteSpace)!) { (user, error) in
if error != nil{
KRProgressHUD.dismiss()
SCLAlertView().showError("Login Error", subTitle: error!.localizedDescription)
}
else {
KRProgressHUD.dismiss()
if user!.emailVerified{
currentUser = user
enableSync()
self.callHomescreen()
}
else
{
AlertView().showError("Login Error", subTitle: "This email is has not been verified yet")
}
}
}
}
Or else in my feed back screen there are some text fields. And the model class is :
var feedbackData = [files]()
class files {
// having some string variables
}
By using this, if my data is empty in my feedback screen redirect the user to feedback screen or else redirect them to home screen. Can we do that?
Updated :
if profileData.FirstName.characters.count <= 0 {
print("Home screen calling")
}
else if profileData.FirstName.characters.count > 0 {
print("feedback screen calling")
}
Thought of trying like this. But no use.
If I understand your question currectly, once user is logged in, you want to check the creation date of the use account. To do so you have two options:
The server side. If you are using Firebase database just add the date of creation. Firebase documantation does not offer a method to get the creation date on the app side.
The app side. User user defaults, when the user login in the first time set the date for that user. When you get to the login screen again, check for existance. I would reccomend using the user id as the key.
For example:
Your user just logged in, you want to check if it the first time that he did:
if let displayName = FIRAuth.auth()?.currentUser?.displayName {
//Make sure we have the user
if UserDefaults.standard.bool(forKey: displayName) {
// try to get the user default for the spacific key
let wasConnected = UserDefaults.standard.bool(forKey: displayName)
if wasConnected {
print("This user was connected")
}
} else {
// This user was never connected
// We set the default to his ID
UserDefaults.standard.set(true, forKey: displayName)
UserDefaults.standard.synchronize()
}
}
To use the date, I think the easiest way is to convert the date to string.
Fiddle with the code to do exactly what you want.

Sign in with different google account Firebase iOS

I am new to iOS and Firebase in general and I'm struggling to find out how I can get the app to show the google oAuth modal when I click the signin button. At the moment, it comes up on the first signup instance, but I have to delete the app to get it working again. This can be a bit cumbersome if someone wants to change google accounts.
// Google Sign In
#IBAction func gooSignInBtn(sender: AnyObject) {
GIDSignIn.sharedInstance().signIn()
}
When I call sign out, it signs out, but the below modal doesn't show up again. It just automatically signs into the last signed in google account.
Does the try! FIRAuth.auth()!.signOut() function only sign out the member temporarily?
#IBAction func signOut(sender: AnyObject) {
try! FIRAuth.auth()!.signOut()
FIRAuth.auth()?.addAuthStateDidChangeListener({ (auth: FIRAuth, user: FIRUser?) in
if let user = user {
// User is signed in.
print(user)
} else {
// No user is signed in.
print("user signed out")
}
})
}
Try adding GIDSignIn.sharedInstance().signOut() for signout

Removing Firebase authState upon viewDidDisappear

I'm using Firebase's new framework and I'm attempting to monitor the login state of the user on both the Login and Signup VC's separately. The problem is if the login state changes on the SignUp view the Auth State on the Login view gets called as well. My question is, how do I remove the auth state? I found the syntax on the Firebase website but am a little confused on what to pass in considering my code for the auth state:
FIRAuth.auth()?.addAuthStateDidChangeListener { auth, user in
if let theUser = user {
// User is signed in.
print("LOGGED IN!!!! :::: \(theUser)")
self.dismissViewControllerAnimated(true, completion: nil)
} else {
// No user is signed in.
print("Need to login first.")
}
}
Code to use to remove the auth, but unsure what to pass in.
FIRAuth.auth()?.removeAuthStateDidChangeListener(FIRAuthStateDidChangeListenerHandle)
Says I pass in a FIRAuthStateDidChangeListenerHandle, but how do I obtain this, or do I rewrite my authState code differently?
Just store the auth in a variable
self.authListener = FIRAuth.auth()?.addAuthStateDidChangeListener { auth, user in
if let theUser = user {
// User is signed in.
print("LOGGED IN!!!! :::: \(theUser)")
self.dismissViewControllerAnimated(true, completion: nil)
} else {
// No user is signed in.
print("Need to login first.")
}
}
and remove it later
FIRAuth.auth()?.removeAuthStateDidChangeListener(self.authListener)

Segue does not work after Facebook Login

For some reason after the user logs in via facebook the segue that takes the user to the profile screen is never executed.
var permissions = ["public_profile", "email"]
PFFacebookUtils.logInWithPermissions(permissions, block: {
(user: PFUser!, error: NSError!) -> Void in
if user == nil {
NSLog("Uh oh. The user cancelled the Facebook login.")
} elseif user.isNew {
println("the user is new")
NSLog("User signed up and logged in through Facebook!")
// THIS WORK
println("THE NEW USER FACEBOOK HAS LOGGED IN AND IS READY TO JUMP TO THE NEXT SCREEN")
//BUT THIS DOESN'T
self.performSegueWithIdentifier("jumpToSignUp", sender: self)
} else {
NSLog("User logged in through Facebook!")
}
})
in the code above, this line never get executed:
self.performSegueWithIdentifier("jumpToSignUp", sender: self)
The user can login via fb, the record get stored in parse, but the it never jumps to the (next)sign up screen.
I have verified that the segue identifier is correct. The weird part is that there is no error in the logs.
any ideas, why this might be happening?
I figured it out - my code is correct. The problem was the next screen. I had some IBOutlets that were not properly set up. I fixed it and it worked again. Just make sure that everything in your next screen is set up properly otherwise the segue will not work.

Resources