drc
drc

Reputation: 1915

Facebook iOS SDK Not Calling Completion Handler

Problem:

Using the FB SDK and the method openActiveSessionWithReadPermissions, the completion handler doesn't appear to get called when the app is reopened from Facebook web or Facebook app and I get this error output:

FBSDKLog: FBSession INVALID transition from FBSessionStateCreated to FBSessionStateClosed FBSDKLog: FBSession transition from FBSessionStateCreated to FBSessionStateCreatedOpening

Context

Steps taken to resolve

Searched throughout Stack Overflow, found similar issues mentioned but not a solution

Specifics:

These are the steps I took to implement Facebook connectivity within the app.

Highlevel steps in code:

Code

AppDelegate.m

- (void)applicationDidFinishLaunching:(UIApplication *)application 
{   
// set up facebook logging
    [FBSettings setLoggingBehavior:[NSSet setWithObjects:FBLoggingBehaviorFBRequests, FBLoggingBehaviorFBURLConnections, FBLoggingBehaviorAccessTokens, FBLoggingBehaviorSessionStateTransitions, nil]];

    // Call the ACAccountStore method renewCredentialsForAccount, which will update the OS's understanding of the token state
    ACAccountStore *accountStore;
    ACAccountType *accountTypeFB;
    if ((accountStore = [[ACAccountStore alloc] init]) &&
        (accountTypeFB = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook] ) ){

        NSArray *fbAccounts = [accountStore accountsWithAccountType:accountTypeFB];
        id account;
        if (fbAccounts && [fbAccounts count] > 0 &&
            (account = [fbAccounts objectAtIndex:0])){

            [accountStore renewCredentialsForAccount:account completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) {
                //we don't actually need to inspect renewResult or error.
                if (error){

                }
            }];
        }
    }

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    // We need to properly handle activation of the application with regards to Facebook Login
    // (e.g., returning from iOS 6.0 Login Dialog or from fast app switching).
    NSLog(@"Calling app did become active");
    [FBSession.activeSession handleDidBecomeActive];
}

/*
 * Callback for session changes.
 */
- (void)sessionStateChanged:(FBSession *)session
                      state:(FBSessionState) state
                      error:(NSError *)error
{
    NSLog(@"Session State Changed");

    switch (state) {
        case FBSessionStateOpen:
            if (!error) {
                // We have a valid session
                NSLog(@"User session found");
            }
            break;
        case FBSessionStateClosed:
        case FBSessionStateClosedLoginFailed:
            [FBSession.activeSession closeAndClearTokenInformation];
            break;
        default:
            break;
    }

    [[NSNotificationCenter defaultCenter]
     postNotificationName:FBSessionStateChangedNotification
     object:session];

    if (error) {
        UIAlertView *alertView = [[UIAlertView alloc]
                                  initWithTitle:@"Error"
                                  message:error.localizedDescription
                                  delegate:nil
                                  cancelButtonTitle:@"OK"
                                  otherButtonTitles:nil];
        [alertView show];
    }
}

/*
 * Opens a Facebook session and optionally shows the login UX.
 */
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI {
    NSLog(@"Openning session with Facebook");
    return [FBSession openActiveSessionWithReadPermissions:nil
                                              allowLoginUI:allowLoginUI
                                         completionHandler:^(FBSession *session,
                                                             FBSessionState state,
                                                             NSError *error) {
                                             [self sessionStateChanged:session
                                                                 state:state
                                                                 error:error];
                                         }];
}


/*
 * If we have a valid session at the time of openURL call, we handle
 * Facebook transitions by passing the url argument to handleOpenURL
 */
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {
    // attempt to extract a token from the url
    NSLog(@"Calling open URL");
    return [FBSession.activeSession handleOpenURL:url];
}

- (void) closeSession {
    NSLog(@"Clossing Facebook Sessions");
    [FBSession.activeSession closeAndClearTokenInformation];
}

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
    NSLog(@"handleOpenUrl Called");
    return [FBSession.activeSession handleOpenURL:url];

}

View Controller with button

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

    // Register for Facebook change notification
    [[NSNotificationCenter defaultCenter]
     addObserver:self
     selector:@selector(sessionStateChanged:)
     name:FBSessionStateChangedNotification
     object:nil];
}

- (IBAction)login:(id)sender {
    ATIAppDelegate *myAppDelegate = (ATIAppDelegate *)[[UIApplication sharedApplication]delegate];
     [myAppDelegate openSessionWithAllowLoginUI:YES];
}

What I think the issue could be?

Upvotes: 2

Views: 4218

Answers (2)

Calvin Alvin
Calvin Alvin

Reputation: 2468

If you don't want the app to run in the background, you can bind to the FBSDKApplicationDelegate in your AppDelegate like so:

import UIKit
import FBSDKLoginKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
    }

    func applicationWillResignActive(_ application: UIApplication) {
        FBSDKAppEvents.activateApp()
    }

    func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
        return FBSDKApplicationDelegate.sharedInstance().application(application, open: url, sourceApplication: sourceApplication, annotation: annotation)
    }
}

https://forums.developer.apple.com/thread/50332 http://ashishkakkad.com/tag/fbsdkapplicationdelegate/

Upvotes: 0

drc
drc

Reputation: 1915

Okay I figured it out - the issue was nothing to do with FB itself, the app (I'm working on updating someone else's code) had a setting in the .plist - 'Application does not run in background' set to true.

Meaning that once the app was relaunched from the Facebook app or Facebook mobile site it wasn't prepared to handle the next step.

enter image description here

Upvotes: 3

Related Questions