DiligentDev DiligentDev - 4 months ago 80
Swift Question

PFLoginViewController: Facebook Log In Not Working - PFUser is nil (Swift & Parse Server)

I'm trying to integrate the Facebook login/signup into my app to work alongside the standard login/signup with email. I am using Swift and have migrated to Parse Server.

I've followed the Parse iOS guide on Facebook Users. When the user taps on the "Log in with Facebook" button, the Xcode console prints that the PFUser is nil but has an access token and a userID.

My goal is to allow the user to login with Facebook. I have the sign up with email part covered. If the user never made an account, and taps on the Log in with Facebook button, I expect the

if user.isNew
block to execute. If the user has made an account before using email signup and taps on the Log in with Facebook button, I expect the
else
block to execute an associate that existing PFUser to their Facebook account. After a successful login/signup, it should show the user the Home page.

The Facebook login dialog is shown to the user, the user authenticates via Facebook, but a
PFUser
is never created. The
if let user = user
block is never executed - it always executes the
else
block and prints "User cancelled the Facebook login." I am not sure what the problem is. Appreciate any help!

Source: https://parse.com/docs/ios/guide#users-facebook-users

func fbLoginButtonTapped() {
print("fbLoginButtonTapped")

let permissions = ["public_profile", "email"]
PFFacebookUtils.logInInBackgroundWithReadPermissions(permissions, block: {
(user: PFUser?, error: NSError?) -> Void in

if let user = user {
if user.isNew {
print("User signed up and logged in through Facebook!")
} else {
print("User logged in through Facebook!")

if !PFFacebookUtils.isLinkedWithUser(user) {
PFFacebookUtils.linkUserInBackground(user, withReadPermissions: nil, block: {
(succeeded: Bool?, error: NSError?) -> Void in
if error == nil {
print("Woohoo, the user is linked with Facebook!")
} else {
print("User is not linked with Facebook.")
}
})
}


dispatch_async(dispatch_get_main_queue(), { () -> Void in
let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("HomeNavigationController") as! UINavigationController
self.presentViewController(viewController, animated: true, completion: nil)
})

}
} else {
print("User cancelled the Facebook login.")
}

print("user: \(user)")
print("user token: \(FBSDKAccessToken.currentAccessToken().tokenString)")
print("user userid: \(FBSDKAccessToken.currentAccessToken().userID)")


}

Answer

I don't know if you already had or tried this already but I was in a very similar situation as you and what fixed it for me was this:

In AppDelegate.swift, the ParseClientConfiguration must be initialized BEFORE the Parse Facebook Utils initialization in didFinishLaunchingWithOptions:

...

// *** Initialize Parse. ***
let config = ParseClientConfiguration(block: {
    (ParseMutableClientConfiguration) -> Void in
    ParseMutableClientConfiguration.applicationId = appKey;
    ParseMutableClientConfiguration.clientKey = clientKey;
    ParseMutableClientConfiguration.server = serverURL;
});

Parse.initializeWithConfiguration(config);

// *NOTE: Putting the following line after after Parse.initializeWithConfiguration(config) fixed the issue
// After this change, the user is no longer nil and does not print "Uh oh. The user cancelled the Facebook login.". Instead, it executes the `if let user = user` block
PFFacebookUtils.initializeFacebookWithApplicationLaunchOptions(launchOptions)

...

Hope this helps at least somebody!

Comments