项目常见崩溃10(陆续更新)

做国际化的app, facebook登录是一定少不了的, 今天介绍一种facebook登录引起的崩溃.

先看堆栈

Thread 0 (crashed)
 0  libobjc.A.dylib!objc_msgSend + 0x1c
    Found by: given as instruction pointer in context
 1  SafariServices!__75-[SFAuthenticationViewController dismissViewControllerAnimated:completion:]_block_invoke + 0x1c
    Found by: previous frame's frame pointer
 2  UIKit!-[UIPresentationController transitionDidFinish:] + 0x524
    Found by: previous frame's frame pointer
 3  UIKit!-[_UICurrentContextPresentationController transitionDidFinish:] + 0x28
    Found by: previous frame's frame pointer
 4  UIKit!__56-[UIPresentationController runTransitionForCurrentState]_block_invoke_2 + 0xb8
    Found by: previous frame's frame pointer
 5  UIKit!-[_UIViewControllerTransitionContext completeTransition:] + 0x70
    Found by: previous frame's frame pointer
 6  UIKit!-[UITransitionView notifyDidCompleteTransition:] + 0xf8
    Found by: previous frame's frame pointer
 7  UIKit!-[UITransitionView _didCompleteTransition:] + 0x464
    Found by: previous frame's frame pointer
 8  UIKit!-[UITransitionView _transitionDidStop:finished:] + 0x74
    Found by: previous frame's frame pointer
 9  UIKit!-[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 0x134
    Found by: previous frame's frame pointer
10  UIKit!-[UIViewAnimationState animationDidStop:finished:] + 0x124
    Found by: previous frame's frame pointer
11  UIKit!-[UIViewAnimationState animationDidStop:finished:] + 0x1c4
    Found by: previous frame's frame pointer
12  QuartzCore!CA::Layer::run_animation_callbacks(void*) + 0x118
    Found by: previous frame's frame pointer
13  libdispatch.dylib!_dispatch_client_callout + 0xc
    Found by: previous frame's frame pointer
14  libdispatch.dylib!_dispatch_main_queue_callback_4CF$VARIANT$mp + 0x3f4
    Found by: previous frame's frame pointer
15  CoreFoundation!__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 0x8
    Found by: previous frame's frame pointer
16  CoreFoundation!__CFRunLoopRun + 0x7d8
    Found by: previous frame's frame pointer
17  CoreFoundation!CFRunLoopRunSpecific + 0x1b0
    Found by: previous frame's frame pointer
18  GraphicsServices!GSEventRunModal + 0x60
    Found by: previous frame's frame pointer
19  UIKit!UIApplicationMain + 0xcc
    Found by: previous frame's frame pointer
20  Hago!main [main.mm : 18 + 0x10]
    Found by: previous frame's frame pointer
21  libdyld.dylib + 0x1568
    Found by: previous frame's frame pointer

WTF, SFAuthenticationViewController? 好像不是我们的代码哦, 这个实际上是系统的一个VC, 在我们点击facebook登录前, 会引导我们去到一个facebook授权页面, 这个页面就是SFAuthenticationViewController类型的, 在测试中确实很难模拟出这种情况, 因为点击一次登录后就会弹出弹窗, 要我们确认, 这时候按道理是没机会再次点击facebook登录的, 但是如果用户的手机比较卡, 连续点了两次, 但是第二次没传递到按钮时候, 用户已经迫不及待的同意授权, 并唤出SFAuthenticationViewController这时候第二次点击传递到了按钮, 触发了再次弹窗, 这时候再次点击确认就崩溃了.

分析: 我们程序在自动登录的时候, 如果发现facebook不能自动登录(token过期, 概率很小)也会触发弹出弹窗, 但这之前用户如果也点击了facebook登录, 并且点击弹窗的继续, 并且来到SFAuthenticationViewController页面才触发自动登录失败的弹窗, 这时候再次点击弹窗就崩溃了.

代码重现崩溃

- (void)tp_login:(PKTpLoginCallback)callback timeout:(TimeOutHandler)timeout
{
    [self fbNewLogin:callback timeout:timeout];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self fbNewLogin:callback timeout:timeout];
    });
}

在3秒内, 下次弹窗弹出前, 触发弹窗, 并点击继续, 来到SFAuthenticationViewController页面. 3秒到, 再次弹窗, 点击, 崩溃~

还有以下几种堆栈也是类似的问题

Thread 0 (crashed)
 0  libobjc.A.dylib!objc_object::release() + 0x10
    Found by: given as instruction pointer in context
 1  SafariServices!__75-[SFAuthenticationViewController dismissViewControllerAnimated:completion:]_block_invoke + 0x1c
    Found by: previous frame's frame pointer
 2  SafariServices!__75-[SFAuthenticationViewController dismissViewControllerAnimated:completion:]_block_invoke + 0x1c
    Found by: previous frame's frame pointer
 3  UIKit!-[UIPresentationController transitionDidFinish:] + 0x524
    Found by: previous frame's frame pointer
 4  UIKit!-[_UICurrentContextPresentationController transitionDidFinish:] + 0x24
    Found by: previous frame's frame pointer
 5  UIKit!__56-[UIPresentationController runTransitionForCurrentState]_block_invoke.436 + 0xb8
    Found by: previous frame's frame pointer
 6  UIKit!-[_UIViewControllerTransitionContext completeTransition:] + 0x70
    Found by: previous frame's frame pointer
 7  UIKit!-[UITransitionView notifyDidCompleteTransition:] + 0xf8
    Found by: previous frame's frame pointer
 8  UIKit!-[UITransitionView _didCompleteTransition:] + 0x468
    Found by: previous frame's frame pointer
 9  UIKit!-[UITransitionView _transitionDidStop:finished:] + 0x74
    Found by: previous frame's frame pointer
10  UIKit!-[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 0x134
    Found by: previous frame's frame pointer
11  UIKit!-[UIViewAnimationState animationDidStop:finished:] + 0x124
    Found by: previous frame's frame pointer
12  UIKit!-[UIViewAnimationState animationDidStop:finished:] + 0x1c4
    Found by: previous frame's frame pointer
13  QuartzCore!CA::Layer::run_animation_callbacks(void*) + 0x118
    Found by: previous frame's frame pointer
14  libdispatch.dylib!_dispatch_client_callout + 0xc
    Found by: previous frame's frame pointer
15  libdispatch.dylib!_dispatch_main_queue_callback_4CF$VARIANT$mp + 0x3f0
    Found by: previous frame's frame pointer
16  CoreFoundation!__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 0x8
    Found by: previous frame's frame pointer
17  CoreFoundation!__CFRunLoopRun + 0x8dc
    Found by: previous frame's frame pointer
18  CoreFoundation!CFRunLoopRunSpecific + 0x224
    Found by: previous frame's frame pointer
19  GraphicsServices!GSEventRunModal + 0x60
    Found by: previous frame's frame pointer
20  UIKit!UIApplicationMain + 0xe8
    Found by: previous frame's frame pointer
21  Hago!main [main.mm : 18 + 0x10]
    Found by: previous frame's frame pointer
22  libdyld.dylib!start + 0x0
    Found by: previous frame's frame pointer

问题出现在这段代码

FBSDKApplicationDelegate.m
if (@available(iOS 11.0, *)) {
    if ([sender isAuthenticationURL:url]) {
      Class SFAuthenticationSessionClass = fbsdkdfl_SFAuthenticationSessionClass();
      if (SFAuthenticationSessionClass != nil) {
          WEAKIFYSELF
        _authenticationSession = [[SFAuthenticationSessionClass alloc] initWithURL:url callbackURLScheme:[FBSDKInternalUtility appURLScheme] completionHandler:^ (NSURL *aURL, NSError *error) {
          handler(error == nil, error);
            STRONGIFYSELF
          if (error == nil) {
            [self application:[UIApplication sharedApplication] openURL:aURL sourceApplication:@"com.apple" annotation:nil];
          }
          self.authenticationSession = nil;
        }];
        [self.authenticationSession start];
        return;
      }
    }
  }

这里发现是iOS11系统先来一段装B的代码, 就是这段代码造成了后续的崩溃. 这里我的解决办法就是注释掉这段装B的代码, 直接走后面的逻辑. 当然, 还是要直面问题.

stackoverflow已经给出了解决办法.

- (void)tp_login:(PKTpLoginCallback)callback timeout:(TimeOutHandler)timeout
{
    UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
    while (topController.presentedViewController) {
        topController = topController.presentedViewController;
    }
    
    if (![topController isKindOfClass:NSClassFromString(@"SFSafariViewController")])
    {
        [self fbNewLogin:callback timeout:timeout];
    }
}
- (void)fbNewLogin:(PKTpLoginCallback)callback
           timeout:(TimeOutHandler)timeout
{
    [_fbLoginMgr logOut];
    _fbLoginMgr.loginBehavior = FBSDKLoginBehaviorBrowser;
    [_fbLoginMgr logInWithReadPermissions:@[ @"public_profile", @"email", @"user_friends", @"user_birthday", @"user_gender" ] fromViewController:nil handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
        MFLogInfo(LogTag, @"facebook login result.grantedPermissions = %@, error = %@", result.grantedPermissions, error);
        if (error) {
            safetyCallblock(callback, kPKLoginResultTpAuthFailed, error.description, nil);
            MFLogError(LogTag, @"Process error");
        } else if (result.isCancelled) {
            safetyCallblock(callback, kPKLoginResultTpLoginCancel, nil, nil);
            MFLogInfo(LogTag, @"Cancelled");
        } else {
            if (result.token.userID.length > 0) {
                [[NSNotificationCenter defaultCenter] postNotificationName:kPKFbAuthSuccessNotification object:nil userInfo:@{kPKFbAuthInfoKey : result.token.userID}];
            }

            HGTpAuthRes *authInfo = [[HGTpAuthRes alloc] init];
            authInfo.accessToken = result.token.tokenString;
            authInfo.openId = result.token.userID;
            authInfo.tpLoginType = kPKTpLoginTypeFacebook;

            //https://developers.facebook.com/docs/graph-api/reference/user  接口文档

            NSDictionary *parameters = @{ @"fields" : @"id,name,gender,birthday,picture.width(1080).height(1080)" };
            [[[FBSDKGraphRequest alloc] initWithGraphPath:@"me" parameters:parameters] startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
                if (!error && [result isKindOfClass:[NSDictionary class]]) {
                    MFLogInfo(LogTag, @"third parth get userinfo succ");
                    authInfo.tpUserInfo = [self parseUserInfo:result];
                }

                safetyCallblock(callback, kPKLoginResultOk, nil, authInfo);
            }];

            MFLogInfo(LogTag, @"third parth log in succ");
        }
    }];
}

这里在每次调用前都判断下当前present的vc是否是SFSafariViewController的子类, 这样就没问题了, 等待上线看效果.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容