2
votes

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

  • Using Facebook SDK 3.2.1
  • App is built for iOS 5.0+
  • Using xCode 4.6.1
  • Testing on Simulator iOS 5.1
  • Testing on iPhone 4S, running iOS 6.1.2 (not using 6.0 social framework as want to test implementation for 5.0+)
  • Updating an app that was originally built for iOS 3.0 and using an old version of sharekit, but has now been updated for ARC and the share kit implementation I believe has all been commented out - hoping the issue is not a conflict with a old share kit function, can't fin any within the code

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:

  • I have my FB methods set up in AppDelegate
  • In a specific view controller I have a button that calls the openSessionWithAllowLoginUI method to start the login process

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?

  • It seems like it may be something with the tokens?
  • Or maybe the notification center?
  • Note that during testing I've been going and revoking access of the Facebook app to my account and then trying to login again to the app, I see these has caused issues with other users
2
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.drc
I'll add this as the answer when stackoverflow lets me in a few hours.drc
Hey drc, I have the same error, but I don't see 'Application does not run in background' anywhere in .plist. Is that the app main .plist or was that additional .plist that your app has?SasaT
It was in the main .plistdrc
I added an image from the plistdrc

2 Answers

3
votes

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

0
votes

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/