Segue does not work after Facebook Login - ios

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.

Related

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

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

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)

Is it normal to ask "you have already authorize " through Facebook SDK

This is just a question, if I log in once with Facebook login using the latest SDK and then I try to log in again, its asking me "you have already authorize app name". Is it normal or Do I have to change something to avoid it.
In my scenario, I made SSO on in Facebook App Setting this does not resolve the issue!!
Whenever my login window shows, I logout the Facebook and clear the access token, first I thought because of this, this is being asked however, I omitted the code and still it is asking!!
I can post code if necessary!!!
override func viewDidLoad() {
super.viewDidLoad()
fbloginButton.delegate = self
fbloginButton.readPermissions = ["public_profile", "email", "user_friends"]
if (FBSDKAccessToken.currentAccessToken() != nil)
{
var loginM:FBSDKLoginManager = FBSDKLoginManager()
loginM.logOut()
FBSDKAccessToken.setCurrentAccessToken(nil)
}
}
#IBAction func loginFb(sender:AnyObject)
{
fbLoginManager.logInWithReadPermissions(["email"], fromViewController: self.presentingViewController, handler: { (result, error) -> Void in
if (error == nil){
var fbloginresult : FBSDKLoginManagerLoginResult = result
}
})
}
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
NSLog("didCompleteWithResult")
if ((error) != nil)
{
}
else if result.isCancelled {
}
else {
// If you ask for multiple permissions at once, you
// should check if specific permissions missing
if result.grantedPermissions.contains("email")
{
///Here I call a function to get data
}
}
It's been a while since I've worked with the Facebook SDK, but I think when you logout, you just invalidate your current accessToken and end your session, but it does not deauthorize your app.
So, when you login, you just generate a new accessToken for the FB app that you already authorized. You need to login again (to verify your identity), but you don't need to authorize again, hence it's giving you that message.
There's a Graph API call to revoke permissions, if that is what you are looking for.
And if your question is whether this is "normal". Yes, I'd say that's normal. It's a visual indication that you are at that point connecting again with a previously authorized FB app. Avoiding it might work by not sending any permissions, but you generally don't know if an already authorized user is logging in again, or a completely new user. If the latter logs in without permissions, well, your app wouldn't work as supposed too.

How to test if my facebook friendlist function is working in swift

I found a piece of code here on stack overflow which I use to find the facebook friend list of the current user in my app.
Now I want to test that code but, due to the version 2 restrictions I can't find any of my friends because my app is still in development and nobody can use my app. So I cannot find any using friends.
How can I test my friendlist functionality?
I was just dealing with the same problem that you have and it's as WizKid says:
https://developers.facebook.com and login to your account
Go into your app then click the "Roles" tab then the "Test Users" tab
Click "Add" and this window will come up. Authorize the user for your app and add the permissions you want them to give your app.
To add friends just click the "Edit" button then "Manage this test User's friends". Add the friends you want the user to have. (Convenient autocomplete is included for other test users)
After you do the former steps I suggest you also change the test user's name and make them a password. The password can be the same for all your test users. You should also login as the test user ("Edit" again) and change their profile picture to differentiate between them especially if you're using profile pictures.
Here is the annoying part; to be able to see (in your app) the test user's friends that you just set, you have to repeat the following for each of the friends you want to see in your list of facebook friends. (This is assuming that you're not getting "invitable friends")
Reset your simulator
Login using the test user's email and password in the safari popup
Repeat No 7, 8 for every test user (This is to make the friends "facebook friends that have used the app")
Good luck and don't drive yourself crazy :) Hope this helps
Another fix is that the problem may be the login function. Because after I've added the right permissions to my test friend it still failed.
I got it working but the main problem seemed to be my login functions. I wasn't using the FBSDKLoginManager. This was easily implemented by:
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
println("User Logged In")
if ((error) != nil)
{
// Process error
}
else if result.isCancelled {
// Handle cancellations
}
else {
// If you ask for multiple permissions at once, you
// should check if specific permissions missing
if result.grantedPermissions.contains("email")
{
self.performSegueWithIdentifier("loggedIn", sender: self)
//self.returnUserData()
// Do work
}
}
}
func loginButtonDidLogOut(loginButton: FBSDKLoginButton!) {
println("User Logged Out")
}
And then
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//if (FBSDKAccessToken.currentAccessToken() == nil)
//{
// User is already logged in, do work such as go to next view controller.
// self.performSegueWithIdentifier("loggedIn", sender: self)
// self.returnUserData()
//}
//else
//{
let loginView : FBSDKLoginButton = FBSDKLoginButton()
self.view.addSubview(loginView)
loginView.center = self.view.center
loginView.readPermissions = ["public_profile", "email", "user_friends"]
loginView.delegate = self
//}
// Do any additional setup after loading the view.
}
This fixed my problem completely after giving the test friend permission.

How to change a parse's Facebook account custom fields

I am trying to enable login with a Facebook account for my new social app but I need to know how to change custom Facebook accounts fields in parse so I can know if a Facebook user already set up his account or not. I managed to do it with regular accounts but now with Facebook accounts
Here is my method:
PFFacebookUtils.logInInBackgroundWithReadPermissions(permissions) {
(user: PFUser?, error: NSError?) -> Void in
if let user = user {
if user.isNew {
println("User signed up and logged in through Facebook!")
self.performSegueWithIdentifier("procceedToSetup", sender: self)
// I need to change here a parse field named "doneSetUp" with a type of a bool to false.
} else {
self.performSegueWithIdentifier("procceedToApp", sender: self)
}
} else {
println("Uh oh. The user cancelled the Facebook login.")
}
}
When a Facebook user completes the setup he/she will press the complete button and it will change the variable "doneSetUp" to true, I do it so Facebook accounts won't exit the app in the middle of the setup and when they log in back they will access the app without setup.
By the way, I would like to know how can I access Facebook account fields I chose with the permissions array, such as country, profile picture, name, etc...
Thanks for all the helpers!
Jeez, I found the reason.
forgot to put
PFUser.currentUser()?.save()
at the end.

Resources