Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Intermittent close of facebook login page which is integrated with iOS app

Mine is an iOS app in Objective-C and have integrated Facebook SDK for login functionality.

I have a mainview controller where I display my button. On button click belowmentioned code is executed on the button handler.

    FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
    [login
     logInWithReadPermissions: @[@"public_profile", @"email"]
     fromViewController:self
     handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
         if (error) {
             NSLog(@"Process error %@",error.description);
         }
         else if (result.isCancelled) {
             NSLog(@"Cancelled");
         }
         else {
             if ([result.grantedPermissions containsObject:kEmail]) {
                 [self fetchfbUserInfo];
             }
             else {
                 NSLog(@"User Declined permissions");
             }
         }
     }];

When the login page from Facebook is displayed in webview within our app, if the facebook login page is left as is/unattended for some time, it intermittent closes with the following error in the console.

FBSDKLog: ERROR: The SFSafariViewController's parent view controller was dismissed. This can happen if you are triggering login from a UIAlertController. Instead, make sure your top most view controller will not be prematurely dismissed.

Did some reverse engineering and found that this delegate method of FBSDKApplicationDelegate class must be getting invoked for the error message.

- (void)viewControllerDidDisappear:(FBSDKContainerViewController *)viewController animated:(BOOL)animated
{
  if (_safariViewController) {
    [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
                           logEntry:@"**ERROR**:\n The SFSafariViewController's parent view controller was dismissed.\n"
     "This can happen if you are triggering login from a UIAlertController. Instead, make sure your top most view "
     "controller will not be prematurely dismissed."];
    [self safariViewControllerDidFinish:_safariViewController];
  }
}

Any possible causes as to why the login page (or app authorization page if alreay logged-in) closes/dismisses on it's own?

like image 673
Marimuthu Avatar asked Oct 29 '22 23:10

Marimuthu


1 Answers

The default behavior in FB iOS SDK since iOS 9 is to use mobile Safari to authenticate the user (as opposed to the native iOS FB app). When a user tries to login to your app with Facebook but has never logged in to Facebook in mobile Safari (no cookie), Safari loads a page in which the user is offered to "Log in with the Facebook app". Tapping that button takes the user to the FB native app, which causes the Safari page to be dismissed (and your app to move to the background). This in fact cancels the login flow and returns to FBSDKLoginManagerLoginResult block with isCancelled == true.

When the user accepts the permissions in the native FB app and returns to your app, application:openURL:options: is called with fb<your-fb-app-id>:// url (which contains the access token). According to FB SDK login guidelines, this url should be passed along to:

[[FBSDKApplicationDelegate sharedInstance] application:application openURL:url options:options];

However FBSDKApplicationDelegate just ignores the url and returns NO because the login flow was "cancelled" beforehand.

To me this looks like a serious bug in FB SDK.

The only workaround I've found to this problem is this:

- (BOOL) application:(UIApplication*)application openURL:(nonnull NSURL *)url options:(nonnull NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
    BOOL handled = [[FBSDKApplicationDelegate sharedInstance] application:application openURL:url options:options];
    if (!handled) {
        NSMutableDictionary *launchOptions = [NSMutableDictionary new];
        launchOptions[UIApplicationLaunchOptionsSourceApplicationKey] = options[UIApplicationOpenURLOptionsSourceApplicationKey];
        launchOptions[UIApplicationLaunchOptionsAnnotationKey] = options[UIApplicationOpenURLOptionsAnnotationKey];
        launchOptions[UIApplicationLaunchOptionsURLKey] = url;
        return [[FBSDKApplicationDelegate sharedInstance] application:application
                                 didFinishLaunchingWithOptions:launchOptions];
    }

    return handled;
}

The above will actually store the access token inside FB SDK.

In order to continue your login flow, you can observe FBSDKAccessTokenDidChange notification, which will be called following the processing of the FB url above.

like image 186
100grams Avatar answered Nov 15 '22 07:11

100grams