24

I'm using die Facebook SDK 3.1.1 to implement FB Connect in my iOS application. This works fine in the simple case with either the new FB integration (logged in on iOS) or falling back to the normal authorization via web view (I do not have the native Facebook application installed in both cases). The problem occurs when I switch the account on iOS level. Logging out and logging in with a different FB user account.

To log in/authorize I perform:

[FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:allowLoginUI
                                     completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
                                         [self sessionStateChanged:session state:state error:error];
                                     }];

If then get a FBSessionStateClosedLoginFailed every time even though I perform a closeAndClearTokenInformation when that state is reached:

- (void)sessionStateChanged:(FBSession *)session
                  state:(FBSessionState) state
                  error:(NSError *)error
{
    NSLog(@"Session State Changed: %u", [[FBSession activeSession] state]);
    switch (state) {
        case FBSessionStateOpen:
            break;
        case FBSessionStateClosed:
        case FBSessionStateClosedLoginFailed:
            NSLog(@"FBSessionStateClosedLoginFailed ERROR: %@", [error description]);
            [[FBSession activeSession] closeAndClearTokenInformation];
            break;
        default:
            break;
}

However, I receive the same state on every retry. My log says the following:

FBSDKLog: FBSession **INVALID** transition from FBSessionStateCreated to FBSessionStateClosed
FBSDKLog: FBSession transition from FBSessionStateCreated to FBSessionStateCreatedOpening 
FBSDKLog: FBSession transition from FBSessionStateCreatedOpening to FBSessionStateClosedLoginFailed Session State Changed: 257
FBSessionStateClosedLoginFailed TOKEN: (null)
FBSessionStateClosedLoginFailed ERROR: Error Domain=com.facebook.sdk Code=2 "The operation couldn’t be completed. (com.facebook.sdk error 2.)" UserInfo=0xb24cc20 {com.facebook.sdk:ErrorLoginFailedReason=com.facebook.sdk:ErrorLoginFailedReason}

Can anyone reproduce this or has any idea where the problem might lie?

Kathrin Holweger
  • 241
  • 1
  • 3
  • 5
  • I think that I am having the same problem as you. I don't know of any solutions or workarounds yet. – ill_always_be_a_warriors Oct 12 '12 at 14:03
  • how did you turn on the FBSDKLog logging? – ill_always_be_a_warriors Oct 12 '12 at 14:12
  • 4
    I found this method somewhere around here: `[FBSettings setLoggingBehavior:[NSSet setWithObjects:FBLoggingBehaviorFBRequests, FBLoggingBehaviorFBURLConnections, FBLoggingBehaviorAccessTokens, FBLoggingBehaviorSessionStateTransitions, nil]];` – Kathrin Holweger Oct 12 '12 at 14:14
  • BTW, it seems to be working now for me, although I'm not sure why. I had incorporatedd the solution from [this](http://stackoverflow.com/questions/12745235/handle-invalid-accesstoken-with-fbsession-openactivesessionwithreadpermissions-i) problem into my sessionStateChanged handler, but it still wouldn't work. Until I tried again later. For some reason the behaviour now looks like follows. I switch the current working FB user on iOS, in the app the session is open, but a request will fail. On the next attempt a new session with correct token is opened and the next request to FB will work. – Kathrin Holweger Oct 12 '12 at 14:28

6 Answers6

38

Another answer gives a way to manually resync the device with the server. I defined a method called fbRsync to call this code. Make sure to #import <Accounts/Accounts.h> in your implementation file and then define this method:

-(void)fbResync
{
    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){

        }
    }];
}

}

I then call fbResync if openActiveSessionWithReadPermissions yields an error:

[FBSession openActiveSessionWithReadPermissions:permissions
                                   allowLoginUI:YES
                              completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
     if(error)
     {
         NSLog(@"Session error");
         [self fbResync];
         [NSThread sleepForTimeInterval:0.5];   //half a second
         [FBSession openActiveSessionWithReadPermissions:permissions
                                            allowLoginUI:YES
                                       completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
            [self sessionStateChanged:session state:state error:error];
                                       }];

     }
     else
         [self sessionStateChanged:session state:state error:error];
 }];

The half a second delay is likely unnecessary, but it currently gives me piece of mind.

This seems to solve the problem for me. I can now switch between Facebook accounts and am able to log in. Yay!

Community
  • 1
  • 1
ill_always_be_a_warriors
  • 1,546
  • 2
  • 17
  • 33
  • 8
    Possibly better to wrap the bottom block of code into a function called something like `fbAttemptConnection` and then use `[self performSelector:@selector(fbAttemptConnection) withObject:nil afterDelay:0.5]` instead of using `sleepForTimeInterval:` and blocking the thread. – jowie Oct 23 '12 at 12:42
  • Also, this won't be backwards-compatible with iOS 5. And for some reason `fbAccounts` returns an empty array for me, even on iOS 6. http://stackoverflow.com/a/12811583/190657 – jowie Oct 23 '12 at 12:48
  • Instead of using any sort of delay, create a completion block for fbResync to call inside `([accountStore renewCredentialsForAccount:account completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) {}];)`. The only caveat is that if you're calling any methods on FBSession, they have to happen on the main thread, but that's easily solved by wrapping that method in `[[NSOperationQueue mainQueue] addOperationWithBlock:^ {}]` – Kaigi May 29 '13 at 17:37
  • @jowie this happens if you have not allowed YOUR APP to user facebook from settings. – geekay Sep 06 '13 at 06:32
12

I had the same problem. Check that your FB App is enabled in Settings -> Facebook. Mine was disabled (even though I don't remember disabling it) and once I enabled it, it was fixed.

In my test process, I've added and removed my FB App several times from my FB Account, which is linked with my iPhone. It may explain why, magically, my app was disabled.

  • 1
    And check also that you have the last version of Facebook iOS SDK – Pierre-Olivier Simonard Mar 08 '13 at 23:47
  • I had the same problem and I was driving crazy. For the first time the app opened I touched "dont allow" when it asked me for facebook permissions for test purposes. After that it never appeared again. At least I was able to turn it on again on iPhone Settings. – Andre Cytryn Apr 16 '13 at 18:23
3

In ios 6 with fb sdk 3.1.1. Please pass permissions param as "nil or email" in "[FBSessio openActiveSessionWithReadPermissions..." method. Here my code it was works great.

#define IOS_NEWER_OR_EQUAL_TO_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 6.0 )

-(void)showFBLogin
{
    [FBSession.activeSession closeAndClearTokenInformation];

    NSArray *permissions = [NSArray arrayWithObjects:@"email, publish_actions, publish_stream", nil];

#ifdef IOS_NEWER_OR_EQUAL_TO_6
    permissions = nil; or NSArray *permissions = [NSArray arrayWithObjects:@"email",nil];
#endif

    NSLog(@"\npermissions = %@", permissions);
    [FBSession openActiveSessionWithReadPermissions:permissions
                                       allowLoginUI:YES
                                  completionHandler:
     ^(FBSession *session,
       FBSessionState state, NSError *error) {
         NSLog(@"\nfb sdk error = %@", error);
         switch (state) {
             case FBSessionStateOpen:
                 [[FBRequest requestForMe] startWithCompletionHandler:
                  ^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) {
                      if (!error) {
                          //success
                      } 
                  }];
                 break;
             case FBSessionStateClosed:
                 //need to handle
                 break;
             case FBSessionStateClosedLoginFailed:
                 //need to handle
                 break;
             default:
                 break;
         }
     }];
}
loganathan
  • 2,056
  • 2
  • 23
  • 34
1


I have the same problem on 3.1.3 FB SDK with iOS7.1. And I find a solution here. Hope it help!!
I have tried all answers here.
@loganathan nil permissions, @ill_always_be_a_warriors fbResync.
All of those don't work for me.

But I found it will works well when I launch the same code in iPhone 7.1 simulator
(without SSO"Single Sign On")

The same code works well on old version iOS FB SDK(not sure which version, but not 3.13)
(but no SSO will show when try to login)

So, I try to re-write a sample problem. I found several different here.
1. https://developers.facebook.com/docs/ios/getting-started Add new FacebookDisplayName
2. I modify my BundleID for iTune connect but I am not update it back to Faceboook App Dev


After modify those setting, it works on my iOS app with SSO feature.
Hope it help!!

Evan Lin
  • 1,272
  • 1
  • 12
  • 25
0

Did you Try the RenewSystemCredential Methods? Take a look at this post:

Facebook iOS SDK extendAccessToken not Working - fbDidExtendToken not being called

Community
  • 1
  • 1
Hernan Arber
  • 1,626
  • 3
  • 22
  • 35
0

I got the same error. But i used @ill_always_be_a_warriors method: -(void)fbResync but not work for me.

I finally found it's my permissions issue, i removed offline_access permission, it works, hope it helps some one.

William Hu
  • 15,423
  • 11
  • 100
  • 121