Maxwell Maxwell - 6 months ago 22
Swift Question

iOS/Swift: PFFacebookUtils.logInWithPersmissions returns nil user and error

In my app, I login users via Parse's PFFacebookUtil class. If the user exists on the phone (i.e. logged into FB in Settings>Facebook), then everything works as expected.

But if they're not logged in through settings, then the user is taken to a web view to log in. After the user puts in their credentials, the return block should receive a user or an error, but in this case both user and error is nil.

let permissionsArray = ["user_about_me", "email"];
PFFacebookUtils.logInWithPermissions(permissionsArray, block: {
(user: PFUser!, error: NSError!) -> Void in
if user != nil {
//successful login
} else if error != nil{
//unsuccessful login
} else {
//this is what I get
}
}


We are currently running Parse 1.4.2

Answer

The problem is that I wasn't calling FBAppCall.handleOpenURL() in the AppDelegate call:

application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?) 

when I came back from a web auth. By not calling FBAppCall.handleOpenURL(), Parse thinks that we canceled our authentication. Parse documentation states that "user and error are both nil - if the user cancelled authentication by switching back to the application."

This method is supposed to call FBAppCall.handleOpenURL to pass the authentication back to the app. In my case I was also using this call for deep linking and I didn't handle the logic properly. I originally was checking the sourceApplication object to see if it was "com.facebook.Facebook". If it returned true, then I called FBAppCall.handleOpenURL(). When I debugged it today, I noticed the source application is actually "com.apple.mobilesafari". Checking sourceApplication is not the best thing to check anyway (try something like the url.host), but in this case, that was the issue.

Here's the fixed code snippet:

func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?) {
    if (url.host == DEEP_LINKING_HOST) {
       //Deep linking code here...
    } else if sourceApplication == "com.apple.mobilesafari" {
       return FBAppCall.handleOpenURL(url, sourceApplication: sourceApplication, withSession: PFFacebookUtils.session())
   }
}

The point here is that I wasn't calling FBAppCall.handleOpenURL(). As a result, the app thought that I canceled the login and gave me a nil user and error.