iOS/Swift: PFFacebookUtils.logInWithPermissions re

2020-04-09 23:57发布

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

3条回答
够拽才男人
2楼-- · 2020-04-10 00:16

I'm using version 4.10.1 of the Facebook SDK. In this version there is no FBAppCall class. Use FBSDKApplicationDelegate instead and paste this code snippet in the app delegate.

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
    BOOL canOpen = [[FBSDKApplicationDelegate sharedInstance] application:application openURL:url sourceApplication:sourceApplication annotation:annotation];

    return canOpen;
}
查看更多
【Aperson】
3楼-- · 2020-04-10 00:28

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.

查看更多
冷血范
4楼-- · 2020-04-10 00:31

Currently, I cannot see any issues with your code. But I would check for null NSError instead of PFUser, just from my experience.

Here's my solution for what I did in my application using Facebook login with parse, its done in objective-c but I'm sure it will put you on the right track... Make breakpoints in your code and check the values of the PFUser and the NSError or log PFUser and NSError. Also head over to Parse.com and check out their solution for Facebook Login. There is an example application but in Objective-C.

[PFFacebookUtils logInWithPermissions:@[@"public_profile", @"email"] block:^(PFUser *user, NSError *error) {
    if (error) {
        [CBUtility facebookErrorHandler:error];
        return;
    } else {
        if (![CBUtility userHasValidFacebookData:user]) {
            [FBRequestConnection startForMeWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
                if (error) {
                    [CBUtility facebookErrorHandler:error];
                    return;
                }

                NSDictionary *user = (NSDictionary *)result;

                if (!user[@"email"]) {
                    [[[UIAlertView alloc] initWithTitle:@"Facebook Login/Register Error"
                                                message:[NSString stringWithFormat:@"There is no email associated with the current facebook account. The Registration could not proceed! Either login to your facebook account and create one or create a new crossbook account in the Register view."]
                                               delegate:nil
                                      cancelButtonTitle:nil
                                      otherButtonTitles:@"Dismiss", nil] show];
                    [[PFUser currentUser] delete];
                    return;
                }

                [PFUser currentUser][kCBUserFirstNameKey] = user[@"first_name"];
                [PFUser currentUser][kCBUserLastNameKey] = user[@"last_name"];
                [PFUser currentUser][kCBUserDisplayNameKey] = user[@"name"];
                [[PFUser currentUser] setEmail:user[@"email"]];
                [PFUser currentUser][kCBUserGenderKey] = [user[@"gender"] capitalizedString];
                [PFUser currentUser][kCBUserFacebookIDKey] = user[@"id"];

                if ([user[@"birthday"] length] != 0) {
                    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
                    [dateFormatter setDateFormat:@"MM/dd/yyyy"];
                    NSDate *date = [dateFormatter dateFromString:user[@"birthday"]];
                    NSDateFormatter *stringFormatter = [[NSDateFormatter alloc] init];
                    [stringFormatter setDateFormat:@"MMM dd, yyyy"];
                    [PFUser currentUser][kCBUserBirthdateKey] = [stringFormatter stringFromDate:date];
                }

                [[PFUser currentUser] saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {


                    if ([error code] == 203) {
                        [[[UIAlertView alloc] initWithTitle:@"Facebook Login/Register Error"
                                                    message:[NSString stringWithFormat:@"Apparently, the email address %@ has already been taken. Login with the username and password that is associated with the email address %@ and link accounts to allow facebook login by going to settings and link facebook account. If you forgot the password for the account, press 'Forgot Password' and type in the email address.", user[@"email"], user[@"email"]]
                                                   delegate:nil
                                          cancelButtonTitle:nil
                                          otherButtonTitles:@"Dismiss", nil] show];
                        [[PFUser currentUser] delete];
                        return;
                    }

                    if (error) {

                        [[[UIAlertView alloc] initWithTitle:@"Error"
                                                    message:[error localizedDescription]
                                                   delegate:nil
                                          cancelButtonTitle:nil
                                          otherButtonTitles:@"Dismiss", nil] show];
                        [PFUser logOut];
                        return;
                    }

                    [[NSNotificationCenter defaultCenter] postNotificationName:CBLoginRegisterControllerUserDidFinishLoginNotification object:nil];
                    [self dismissViewControllerAnimated:YES completion:nil];
                    [(AppDelegate *)[[UIApplication sharedApplication] delegate] downloadFacebookPhoto];
                    return;
                }];
            }];
            return;
        }

        [[NSNotificationCenter defaultCenter] postNotificationName:CBLoginRegisterControllerUserDidFinishLoginNotification object:nil];
        [self dismissViewControllerAnimated:YES completion:nil];
        [(AppDelegate *)[[UIApplication sharedApplication] delegate] downloadFacebookPhoto];
        return;
    }
}];
查看更多
登录 后发表回答