1

I've got an app that is nearing completion, and we've decided to allow users to login using Facebook.

At some point in the past, this feature was working, and now it simply hangs.

I've included the latest Parse SDK (1.6.1) and the latest Facebook SDK (3.21.1).

I think I've set up the app correctly. Here are the calls that I am making:

// AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [Parse setApplicationId:@"appId" clientKey:@"clientKey"];
    [PFFacebookUtils initializeFacebook];
    return YES;
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
    [FBAppCall handleDidBecomeActiveWithSession:[PFFacebookUtils session]];
}
- (void)applicationWillTerminate:(UIApplication *)application {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    [[PFFacebookUtils session] close];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    return [FBAppCall handleOpenURL:url sourceApplication:sourceApplication withSession:[PFFacebookUtils session]];
}

// Login View Controller
- (void)loginWithFacebok {
    [PFFacebookUtils logInWithPermissions:@[@"public_profile", @"email"] block:^(PFUser *user, NSError *error) {
        if (error != nil) {
            // Error handling here.

        } else {
            if (user == nil) {
                // Something odd happened; error handling here.

            } else {
                // A further Facebook method...
                [self authorizeFacebookPublish];
            }
        }
    }];
}

Basically, although it was working at a previous time, it's non-functional now in the sense that block is never called. I do get the "app jump" to the Facebook app/web page (can't remember which now, and it "jumps" there and back too fast for me to tell, since I've approved this in the past). What's interesting is that if I force-quit the app (the app is basically in a "hung" state) and re-launch the app, the app loads and the user is logged in.

This is a fairly important point, but I can't find anyone else having this particular issue.

I saw this question, but we're not using Twitter.

This question isn't related to Parse.


EDIT: I was working through this more and kept being slightly confused by breakpoint catching. For instance, in my -loginWithFacebook method, I placed a breakpoint on the first line (the loginWithPermissions call) and the first line of the returned block (if (error != nil) {..., and the first breakpoint would be hit twice each time. I finally thought to try something new, so I added an NSLog line above the first line and moved the first breakpoint there. Subsequent runs had the first breakpoint (now on NSLog) hit once and then the first line of the block hit second. Therefore, I was able to determine that my problem is not, in fact, in my loginWithFacebook method. It's in my authorizeFacebookPublish method. Here's that code:
- (void)authorizeFacebookPublish {
    NSLog(@"authorizing for Facebook publish..."); // First breakpoint here...
    [PFFacebookUtils reauthorizeUser:[PFUser currentUser]
              withPublishPermissions:@[@"publish_actions"]
                            audience:FBSessionDefaultAudienceFriends
                               block:^(BOOL succeeded, NSError *error) {
                                   if (error != nil) { // Second breakpoint here...
                                       // Error handling...

                                   } else {
                                       if (succeeded == YES) {
                                           // Our app now has publishing permissions for the user
                                           [PFUser currentUser][@"canPublishToFacebook"]    = @(YES);

                                       } else {
                                           // Our app was refused publishing permissions
                                           [PFUser currentUser][@"canPublishToFacebook"]    = @(NO);

                                           [[PFUser currentUser] saveInBackground];                                           
                                       }
                                       // Log in was successful, so do other stuff.... 
                                   }                               
                               }];
}

I'm now seeing the issue that's also listed here, which is that some breakpoint (apparently named "breakpoint 2.1" is being hit each time). This guy, however, isn't reporting the same problem I'm seeing, which is that the return block is never firing. Therefore, I am concluding that there is some problem in the authorization (or maybe re-authorization) block.

As I mentioned above, this code was working at some point in the past. Is it possible that "re-authorizing" causes an error? Is there a way for me to check whether the user has already authorized my app in the past and skip the authorization process (since it's already been done)? If that IS the problem, what's the correct procedure for logging a user back in after a logout (using Facebook)?

Community
  • 1
  • 1
mbm29414
  • 11,558
  • 6
  • 56
  • 87
  • Are you sure the completion block's not running? What happens if you comment out "[self authorizeFacebookPublish];"? – Lyndsey Scott Dec 31 '14 at 00:46
  • Did you return YES from handleOpenURL in delegate? I think you did. – Jun Dec 31 '14 at 03:44
  • @LyndseyScott I have a breakpoint at the first line of the completion block. My code never gets to `[self authorizeFacebookPublish]` at all anymore. – mbm29414 Dec 31 '14 at 09:54
  • @Harry Yes. Or at least, I think that's what `return [FBAppCall handleOpenURL:url sourceApplication:sourceApplication withSession:[PFFacebookUtils session]];` does. As I mentioned in the post, the app does go to and return from Facebook's app/web page, so I don't *think* that's the issue. – mbm29414 Dec 31 '14 at 09:55
  • Try logging the value of _user_ and _error_ before the line `if(error != nil)` and let me know. – Jun Dec 31 '14 at 12:06
  • @Harry I cannot do that as it never reaches that point. That's what I'm saying. Control never enters `block`. It simply is never called. That's basically the entirety of my problem. – mbm29414 Dec 31 '14 at 13:39
  • Are you sure the method itself, `loginWithFacebok`, is ever being called? – Lyndsey Scott Jan 01 '15 at 19:46
  • @Harry Please see my update. It's actually failing in the authorize method, not the login method. – mbm29414 Jan 02 '15 at 14:18

1 Answers1

1

First of all, why are you calling [[PFFacebookUtils session] close] in your applicationWillTerminate: callback ? The Facebook session uses a token stored on disk, which means the session is kept open across app launches and has no reason to be closed when the app is terminated.

If you want to log the user out, you should call [PFUser logOut] and then [[PFFacebookUtils session] close] or better [[PFFacebookUtils session] closeAndClearTokenInformation] (but I'm not sure this is even necessary). If you don't want to log the user out (which I think is better), just don't call anything.

Secondly, I too have had a lot of problems in the past with [PFFacebookUtils reauthorizeUser: ...]. One workaround that I found was to use the Facebook API directly :

[[PFFacebookUtils session] requestNewPublishPermissions:[NSArray arrayWithObject:@"publish_actions"] defaultAudience:FBSessionDefaultAudienceFriends completionHandler:^(FBSession *session, NSError *error) {
    if (!error) {
        if ([[PFFacebookUtils session].permissions indexOfObject:@"publish_actions"] == NSNotFound) {
            // Permission not granted, tell the user we will not share to Facebook
            NSLog(@"Permission not granted, we will not share to Facebook.");
        } else {
            // Permission granted.
        }
    } else {
        // An error occurred. See: https://developers.facebook.com/docs/ios/errors
        NSLog(@"Error : Requesting \"publish_actions\" permission failed with error : %@", error);
    }
}];

It does exactly the same thing but seems to be working better.

Also, concerning your multiple breakpoint issues, if you put a breakpoint at the beginning of a block, it will usually stop twice : when the block is created and when the block is called. The block is only called once though, you can check that with an NSLog(...) call as you did.

deadbeef
  • 5,409
  • 2
  • 17
  • 47
  • Thank you for your help. I am currently testing your answer, but I think it's working for me! If it last through some testing, I'll come back and accept your answer. In answer to your question about why I'm calling `[[PFFacebookUtils session] close]` in `applicationWillTerminate:`, it's the pattern **recommended by Parse** on [this page](https://parse.com/tutorials/integrating-facebook-in-ios). I need to do some further investigation to see whether it's necessary/preferable in my scenario. – mbm29414 Jan 05 '15 at 20:09
  • You're right, thanks for pointing that out ! I wonder why though, it seems very strange to me, but maybe there is a reason... – deadbeef Jan 05 '15 at 21:39
  • As I've thought it through, I'm assuming it's for a very secure app that requires the user to re-login with each app launch. But then, I'd also expect a call to `[PFUser logOut]` at the same time. I don't really know what to do with the code "as-is", and now that Parse has no real Support forums... I dunno, I guess I'll leave that issue for now. – mbm29414 Jan 06 '15 at 01:03