26

I am having trouble figuring out how to log a user into my app. [FBSDKAccessToken currentAccessToken] is nil, so I am calling:

[[[FBSDKLoginManager alloc] init] logInWithPublishPermissions:@[@"publish_actions"] handler:…];

as per the included sample project. This switches to the Facebook app, but the message says "You have already authorized App Name.". I click OK and it goes back into the app, but grantedPermissions and declinedPermissions are both nil on the result, and isCancelled is YES. [FBSDKAccessToken currentAccessToken] is still nil.

I can't figure out how I'm supposed to get currentAccessToken to be filled in. It seems to me the call to logInWithPublishPermissions should do that, but it isn't.

devios1
  • 36,899
  • 45
  • 162
  • 260

11 Answers11

50

You should try adding in your AppDelegate didFinishLaunchingWithOptions :

return [[FBSDKApplicationDelegate sharedInstance] application:application
                                    didFinishLaunchingWithOptions:launchOptions];

This would get u [FBSDKAccessToken currentAccessToken] when user is logged in.

and

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

If this method is not present into AppDelegate then it results into cancelled state.

Refer to : https://developers.facebook.com/docs/ios/getting-started#startcoding

Dheeraj Singh
  • 5,143
  • 25
  • 33
29

This can happen when your Facebook App doesn't have "publish_actions" permission, or you're not using a test user.

On Facebook, go to manage your app, then make sure that the Facebook user you're using is defined under "Roles" as an admin or tester.

If it's not a test user or admin - Facebook will require "publish_actions" permission to be reviewed and approved before allowing your app to use it, until then you'll receive a "isCancelled=YES" result.

After testing your app with this permission, it is possible to submit this permission for review, you'll need to upload a binary that demonstrates usage of this permission with exact details on how to use it. After it's approved, you'll be able to use it with non-test Facebook users.

Kof
  • 23,893
  • 9
  • 56
  • 81
  • 2
    Wow, this was the solution. So much time to understand why I always get iscancelled = YES... MANY thanks Kof. – Franck May 22 '15 at 00:59
  • This was also the solution for me. I had done all that other stuff but was on a different device that was logged into a different account that wasn't a test user. – Kevin Heap Sep 12 '15 at 19:16
  • I added `publish_actions` when calling `FBSDKLoginManager().logInWithPublishPermissions()` but it is still not working :( – Hlung Oct 11 '15 at 14:00
2

Since FBSDKLoginKit 4.6.0, the logInWithReadPermissions and logInWithPublishPermissions methods of FBSDKLoginManager seems to have additional fromViewController argument and use that to present modals.

I was calling logInWithPublishPermissions inside the callback of logInWithReadPermissions, which at that point the modal is not fully dismissed yet. (I know it's a bad practice to ask permission when it's not needed, but in my case this seems to be the right place to do.) This cause it to fail with isCancelled equals to YES. I added some delay and wait for the modal to be fully dismissed fixed the problem.

Hlung
  • 13,850
  • 6
  • 71
  • 90
  • If you only need `public_profile` read permission, you can just ask for publish permissions without having read permissions in advance. The SDK will handle it by itself by first asking the user for `public_profile`, then the write permissions you requested. This saves you from handling the dialog flow by yourself. – endowzoner Jan 21 '16 at 16:16
2

I had the same problem when I landed here, turns out I was only using the deprecated application openURL method because i was using google sign in too. To support iOS 8 and before you have to implement both the current and the deprecated method:

func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
    return GIDSignIn.sharedInstance().handle(url, sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String!, annotation: options[UIApplicationOpenURLOptionsKey.annotation]) || FBSDKApplicationDelegate.sharedInstance().application(app, open: url, sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String, annotation: options[UIApplicationOpenURLOptionsKey.annotation])
}

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

The deprecated is the second.

Note: The FBSDK method is added after the google one with an or "||" operator but the order doesn't matter and if you wanna only use facebook method just erase the method and the or operator.

Note 2: As swift 3 still stabilizing the method name can change I suggest you always use the auto complete from XCode when overriding and implementing a delegate's method.

Hope this Helps o/

1

FBSDKLoginManagerLoginResult.isCancelled is unexpectedly YES:

The SDK will report a cancellation if the user explicitly taps a cancel button in the login dialogs, or if they manually app switch back to your app (known as an implicit cancellation). You should make sure you are not initiating a login flow as part of your app delegate's lifecycle (such as starting a login inside application:openURL:sourceApplication:annotation:) as that will mimic an implicit cancellation. If you must, dispatch the login initiation later to the main queue so that the app delegate's lifecycle completes first.

sschale
  • 5,168
  • 3
  • 29
  • 36
Salman Ghumsani
  • 3,647
  • 2
  • 21
  • 34
1

This method works in iOS 9

// Facebook Login Completion delegate
- (void)loginButton:(FBSDKLoginButton *)loginButton didCompleteWithResult:(FBSDKLoginManagerLoginResult *)result error:(NSError *)error
{
    if (result){
        NSLog(@"%@",result);
        NSLog(@"%@",result.grantedPermissions);
       [self getFacebookData:result];
     }
}  

- (void)getFacebookData:(FBSDKLoginManagerLoginResult *)result{

   if (![result.grantedPermissions containsObject:@"email"])
   {
      FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
      login.loginBehavior = FBSDKLoginBehaviorWeb;
      [login logInWithReadPermissions:@[@"email"] fromViewController:self handler:^(FBSDKLoginManagerLoginResult *result, NSError *error)
       {
         if (error)
         {
             // Process error
         }
         else if (result.isCancelled)
         {
             // Handle cancellations
         }
         else
         {
             if ([result.grantedPermissions containsObject:@"email"])
             {
                 NSLog(@"result is:%@",result);
                 if ([FBSDKAccessToken currentAccessToken]) {
                     [[[FBSDKGraphRequest alloc] initWithGraphPath:@"me" parameters:@{@"fields": @"first_name, last_name, email, id"}]
                      startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
                          if (!error) {
                              NSLog(@"fetched user:%@", result);
                              [self registerWithFacebook:result];
                          }else{
                              NSLog(@"%@",error);
                          }
                      }];
                 }


             }
         }
     }];


 }else{
    if ([FBSDKAccessToken currentAccessToken]) {
        [[[FBSDKGraphRequest alloc] initWithGraphPath:@"me" parameters:@{@"fields": @"first_name, last_name, email, id"}]
         startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
             if (!error) {
                 NSLog(@"fetched user:%@", result);
                 [self registerWithFacebook:result];
             }else{
                 NSLog(@"%@",error);
             }
         }];
    }
}

}

NOTE : Use FBSDKLoginBehaviorWeb instead of FBSDKLoginBehaviorBrowser. This will surely work

Jayaraj
  • 342
  • 3
  • 13
0

Also, make sure you are not calling for FBSDKAccessToken.currentAccessToken INSIDE your didFinishLaunchingWithOptions method. The setup in didFinishLaunchingWithOptions needs to complete so the token can initialize before you try to log in to Facebook.

Unheilig
  • 16,196
  • 193
  • 68
  • 98
gravy
  • 181
  • 2
  • 8
0

I also faced the same issue and i spent almost 2 hours to resolve the issue. What i did is

FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
**[login logOut];** // adding this single line fixed my issue
[login logInWithReadPermissions: @[@"public_profile"] fromViewController:self  handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
     if (error) {
         NSLog(@"Process error");
     } else if (result.isCancelled) {
         NSLog(@"Cancelled");
     } else {
         NSLog(@"Logged in");
         [self GetData];
     }
 }] // I called this logout function 

and the issue was fixed

i was using both google and Facebook login so i had to implement my openURL method like this, iOS 9+

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    if ([[url absoluteString] containsString:@"YOURFBID"]) {
        return [[FBSDKApplicationDelegate sharedInstance] application:app openURL:url options:options];
    } else {
        return [[GIDSignIn sharedInstance] handleURL:url
                                   sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]
                                          annotation:options[UIApplicationOpenURLOptionsAnnotationKey]];
    }
    return NO;
}

// you can perform further any operations using the access token

- (void)GetData {
    if ([FBSDKAccessToken currentAccessToken]) {
        NSDictionary *AccessToken = [FBSDKAccessToken currentAccessToken];
        [[[FBSDKGraphRequest alloc] initWithGraphPath:@"me" parameters:@{@"fields": @"id, name, first_name, picture.type(large) ,last_name"}]
         startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
             if (!error) {
                 //NSLog(@"fetched user:%@", result);
                 //NSDictionary *Result = result;
                 NSDictionary *params = [NSMutableDictionary dictionaryWithObject:[AccessToken tokenString] forKey:@"access_token"];

             } else {
                 [self showAlertController:@"Error" message:error.localizedDescription];
             }
         }];
    } }
Adeel Ahmed
  • 161
  • 1
  • 8
0
(BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
            options:(nonnull NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
    return [[FBSDKApplicationDelegate sharedInstance] application:application
                                                          openURL:url
                                                          options:options];
}

// **Still need this for iOS8**
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(nullable NSString *)sourceApplication
         annotation:(nonnull id)annotation
{
    return [[FBSDKApplicationDelegate sharedInstance] application:application
                                                          openURL:url
                                                sourceApplication:sourceApplication
                                                       annotation:annotation];
}
Krishna Mohan
  • 1,503
  • 3
  • 22
  • 28
Cong Wang
  • 3
  • 2
0

1.check already added

[[FBSDKApplicationDelegate sharedInstance] application:application
                             didFinishLaunchingWithOptions:launchOptions];

2.check already added

- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(nullable NSString *)sourceApplication
         annotation:(nonnull id)annotation
{
    return [[FBSDKApplicationDelegate sharedInstance] application:application
                                                          openURL:url
                                                sourceApplication:sourceApplication
                                                       annotation:annotation];
}

3. write this statement [FBSDKProfile enableUpdatesOnAccessTokenChange:YES]; before

[[FBSDKApplicationDelegate sharedInstance] application:application
                         didFinishLaunchingWithOptions:launchOptions];

4.call logInWithReadPermissions method in dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{}

Yong Piao
  • 1
  • 1
-2

call this methord,

FBSDKLoginManager *loginManager = [[FBSDKLoginManager alloc] init];
[loginManager logInWithReadPermissions:@[@"user_friends"] handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
   code
}];
Nazik
  • 8,696
  • 27
  • 77
  • 123