React Native在生产中崩溃

ewo*_*com 11 xcode ios react-native

我们使用React Native构建了一个应用程序,以改进我们以前的Cordova应用程序的UX和功能.

一切都很顺利.几个月的开发,QA,App审查,然后我们发布到App Store.它适用于我们尝试过的所有设备,从iPhone 4s到iPhone 6s +,我们在iOS 8.3(可以通过xCode下载的最早的模拟器)上测试到10.0.

发布后,许多用户开始报告应用程序在启动屏幕崩溃之前崩溃.我们在应用审核,测试或其他任何地方都没有看到的行为.

我们调查了xCode中的"崩溃"并且它们显然没有出现,因为数百名用户遇到了崩溃,我们只能看到很少 - 这似乎与启动无关.

我们发布了集成了Crashlytics的更新版本,但这也没有帮助.对于这个特定问题,我们也没有得到Crashlytics错误,这意味着问题可能在之前发生

我应该在哪里看到下一个想法?我们真的不想恢复旧版本而失去数月的工作.

当一切都被加载时,应用程序使用大约100MB的内存,所以这不应该是我认为的问题.所有设备上的所有iOS版本都会发生这种情况.我们无法将错误隔离到特定用户.

Son*_*ach 5

当似乎没有任何其他分析途径时,我会采用简陋的伐木方式.

我以前在生产iOS应用程序中使用了以下技术.这是一项设置工作,但一旦开始,它对未来的许多其他问题非常有用.不只是崩溃,而是用户报告您在测试环境中无法复制的任何其他奇怪行为.

  1. 应用程序应该做的第一件事是通过读取一些应该在上一次启动的开始和结束时写入默认值的值来检查PREVIOUS启动是否成功(下一步中的详细信息).如果PREVIOUS启动不成功,请为用户提供以某种"安全模式"运行的选项(这意味着取决于您的应用在启动时尝试做什么,但对我而言,这意味着不加载任何数据或执行除了显示没有任何数据依赖项的UI之外的任何东西;对于某些应用程序,它甚至可以加载完全不同的UI,其中仅包括诊断工具或数据删除/重置工具).
  2. 应用程序在确定上一次启动是否正常(或者这是第一次启动之后)应该做的下一件事是尽快将某种"startupBegan"状态写入默认值然后再某种" startupCompleted"状态仅在完全启动时完成("完全启动"意味着依赖于应用程序,但您确实希望UI在此时完全响应,并且正在显示它需要的所有内容;这可以有时确定有点棘手,因为有些东西直到启动画面消失后才会运行等等;如果你找不到任何其他方式,我想你可以用计时器触发它,但那会相当难看 - 最好找到一些方法来确定何时启动真的完全完成).这些值可用于确定启动是否开始,但未完成,并且是步骤1(上面)用于确定先前启动是否成功的步骤.
  3. 在应用程序中包含大量日志记录,并将日志写入文件.我认为你可以使用第三方工具,但是我编写了自己的方法(如下所示),如果在生产环境中运行并且未连接到XCode,则只需将stderr重定向到文件.请注意NSLog()写入stderr,而不是stdout.
  4. 使应用程序能够将日志文件通过电子邮件发送到您的支持电子邮件地址 - 这必须在应用程序的"安全模式"(以及正常模式下)中提供.在正常模式下,我将其设置为相当模糊,以便在一切顺利时(例如,"设置"或"关于"视图底部的按钮)不会被用户注意到太多.我告诉用户当他们提交了我真正需要日志的支持请求时如何找到该按钮.
  5. 在每次启动时旋转日志以防止它们占用太多空间,但一定要保持一些旋转,否则你只能从"安全模式"启动获取日志,这是无用的.

对此有很多变化是可能的.包括仅在用户为其配置设置时启用日志记录的内容.有时,当用户报告特定问题时,您可能必须在特定代码区域添加大量日志记录,然后在问题解决后再次将其删除(如果您担心日志记录的性能/存储问题).

对于我的(Objective-C)应用程序,包含我的代码以将启动状态写入默认值的位置如下(可能有更适合您的应用的更好的地方):

  • "startupBegan"在应用代表的早期 application:didFinishLaunchingWithOptions:
  • 在视图控制器的末尾"startupCompleted" viewDidAppear(不是viewWillAppear!这两个被发送之间有很多东西可能会出错)

PS.我的旧日志重定向和循环方法是这样的(Objective-C):

- (void)logRedirectRotate {
    // If stderr not going to an XCode console (then running in production)
    if ( ! isatty(STDERR_FILENO) ) {
        // Rotate logs

        int rotationsCount = 3;
        NSMutableArray *logRotations = [NSMutableArray array];

        for ( int i = 0; i < rotationsCount; i++ ) {
            [logRotations addObject:[pathToLogsDir stringByAppendingPathComponent:[NSString stringWithFormat:@"appnameorbundleid.%d.log", i]]];
        }

        [[NSFileManager defaultManager] removeItemAtPath:[logRotations lastObject] error:nil];

        for ( int i = rotationsCount - 1; i > 0; i-- ) {
            [[NSFileManager defaultManager] moveItemAtPath:[logRotations objectAtIndex:i - 1] toPath:[logRotations objectAtIndex:i] error:nil];
        }

        //  Redirect stderr to current log file rotation
        freopen([[logRotations objectAtIndex:0] cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
    }
}
Run Code Online (Sandbox Code Playgroud)


ewo*_*com 3

由于我们和用户之间的沟通不畅,这个问题花了很长时间才得到解决。应用程序实际上并没有崩溃,只是没有启动(在某些用户看来也是如此)。

在我们发现这一点之后,我们意识到其中一个事件没有触发(隐藏扩展启动屏幕的事件),这就是用户陷入困境的地方。我们使用的库之一没有正确处理错误场景,这使我们的工作变得更加困难。我很幸运能够在测试时进入这种状态,并且可以从那里继续。

我更新了代码来处理这种情况,问题现已解决。