web-dev-qa-db-fra.com

Crash de Safari Services [SFAuthenticationViewController rejetViewControllerAnimated: complétion:]

J'ai très souvent un crash dans mon application. Il semble qu'un crash du système iOS ne se produise que dans le dernier iOS 11. 

C'est le crash

Crashed: com.Apple.main-thread
0  libobjc.A.dylib                0x18439d7ec objc_object::release() + 8
1  SafariServices                 0x1995d471c __75-[SFAuthenticationViewController dismissViewControllerAnimated:completion:]_block_invoke + 32
2  UIKit                          0x18e5bf030 -[UIPresentationController transitionDidFinish:] + 1320
3  UIKit                          0x18e79e760 -[_UICurrentContextPresentationController transitionDidFinish:] + 44
4  UIKit                          0x18e5c2a20 __56-[UIPresentationController runTransitionForCurrentState]_block_invoke_2 + 188
5  UIKit                          0x18e38e9d8 -[_UIViewControllerTransitionContext completeTransition:] + 116
6  UIKit                          0x18e38e7c8 -[UITransitionView notifyDidCompleteTransition:] + 252
7  UIKit                          0x18e38e260 -[UITransitionView _didCompleteTransition:] + 1128
8  UIKit                          0x18e38dde4 -[UITransitionView _transitionDidStop:finished:] + 120
9  UIKit                          0x18e2b370c -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 312
10 UIKit                          0x18e2b3418 -[UIViewAnimationState animationDidStop:finished:] + 296
11 UIKit                          0x18e2b34b8 -[UIViewAnimationState animationDidStop:finished:] + 456
12 QuartzCore                     0x188e57d6c CA::Layer::run_animation_callbacks(void*) + 284
13 libdispatch.dylib              0x1847f1048 _dispatch_client_callout + 16
14 libdispatch.dylib              0x1847fdb74 _dispatch_main_queue_callback_4CF$VARIANT$mp + 1016
15 CoreFoundation                 0x184e13f20 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
16 CoreFoundation                 0x184e11afc __CFRunLoopRun + 2012
17 CoreFoundation                 0x184d322d8 CFRunLoopRunSpecific + 436
18 GraphicsServices               0x186bc3f84 GSEventRunModal + 100
19 UIKit                          0x18e2df880 UIApplicationMain + 208
20 Jaumo                          0x1005674b4 main (main.m:20)
21 libdyld.dylib                  0x18485656c start + 4

Pas sûr de ce qu'est ce crash. n'importe qui peut aider avec ce problème?

15
Pablo Martinez

Nous avions le même problème après avoir mis à jour le dernier SDK de Facebook (à partir d'une version assez ancienne de 4.11 à 4.27.1). En fait, certains appels initiés à partir de l'événement applicationDidBecomeActive ont déclenché la connexion à Facebook (ouvrez donc une SFAuthenticationSession qui ouvre la SFAuthenticationViewController l'invite qui demande à l'utilisateur de poursuivre l'authentification avec Facebook ou une tierce partie). Une fois que l'utilisateur a appuyé sur "Continuer", l'événement applicationDidBecomeActive a été déclenché. Cela a provoqué une boucle sans fin de démarrage de la nouvelle SFAuthenticaionSessions, ce qui a entraîné un crash. Nous avons donc décidé de ne pas appeler Facebook du compte de cet événement. Pour résumer comment éviter cet incident: vous devez vous assurer que vous appelez la connexion Facebook (ou la méthode SFAuthenticationSessionstart()) une seule fois à la fois.

3
Zoltán Homoki

Comme @ Zoltán Homoki et @Jelly ont dit, nous devrions appeler logInWithReadPermissions une seule fois.

Pour ce faire, une implémentation courante (c'était correct avant) consiste à définir un indicateur dans la variable appDelegate comme:

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
    if ([[url.scheme substringToIndex:2] isEqualToString:@"fb"]) {
        _fromFbConnect = YES; // <- This flag
        returnValue = [[FBSDKApplicationDelegate sharedInstance] application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
    }
    // Manage app deep links here
}

Ensuite, utilisez-le pour empêcher plusieurs appels à la connexion Facebook:

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    [FBSDKAppEvents activateApp];

    if (_fromFbConnect == NO) { // <- Always `YES` on iOS11 with FB SDK 4.27
        // Refresh the facebook token
        if ([FBSDKAccessToken currentAccessToken] != nil) {
            [[FBSDKLoginManager new] logInWithReadPermissions: // ...
        }
        _fromFbConnect = NO;
    }
}

Le problème est que sur iOS11 avec FBSDKLoginKit> = 4.27 application:openURL:sourceApplication:annotation: n'est pas appelé (ni application:openURL:option), de sorte que l'indicateur n'est pas défini. Cela crée plusieurs appels à la connexion (applicationDidBecomeActive étant appelé lorsque l'utilisateur ferme la première fenêtre contextuelle)

La solution que j'ai trouvée consiste à configurer un indicateur avant tout appel de FBSDKLoginManager et à arrêter tout autre appel jusqu'à la fin du processus.

@property (assign, nonatomic) BOOL fbRequesting;

// ...

if(_fbRequesting == YES) {
    NSLog(@"Facebook login already in progress");
    return;
}

if ([FBSDKAccessToken currentAccessToken] != nil) {
    return;
}

_fbRequesting = YES;
[FBSDKProfile enableUpdatesOnAccessTokenChange:YES];

NSLog(@"Logging in to Facebook...");

@weakify(self);
[[FBSDKLoginManager new] logInWithReadPermissions:... fromViewController:... handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
    @strongify(self);

    // Handle login

    _fbRequesting = NO;
    })
];

Cela semble fonctionner avec les versions 4.22 à 4.28 de FBSDKLoginKit.

2
Axel Guilmin

Je viens de faire face à ce crash dans FB SDK 4.31.1, et c'est ce que j'ai résolu.

Dans mon cas, un crash se produit, uniquement lorsque j'essaie de démarrer la connexion au FB, lorsque la connexion au FB a déjà commencé (un écran Safari Web apparaît à l'écran).

Donc je vérifie juste:

UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController) {
       topController = topController.presentedViewController;
    }

if ([topController isKindOfClass:[MyViewController class]])
{
     // If that's my view controller, we can start FB Login
}
1
Torello