React Native在生产中崩溃

时间:2016-11-21 19:30:51

标签: ios xcode react-native

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

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

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

我们调查了"崩溃"在xCode中他们显然没有出现,因为数百名用户遇到了崩溃,我们只能看到很少 - 这似乎与创业无关。

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

之前

我接下来应该关注哪些想法?我们真的不想恢复旧版本而失去数月的工作。

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

3 个答案:

答案 0 :(得分:5)

如果似乎没有任何其他分析途径,我会采用简单的伐木方式。

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

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

    对于我的(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);
        }
    }
    

答案 1 :(得分:2)

由于我们与用户之间的沟通不畅,问题需要很长时间才能解决。应用程序实际上没有崩溃,只是没有启动(在某些用户眼中这是相同的)。

在我们发现之后,我们意识到其中一个事件没有触发(隐藏了扩展的闪屏的事件),这就是用户卡住的地方。我们使用的其中一个库没有正确处理错误情况,这使我们的工作变得更加困难。我很幸运,在测试时进入该状态,我可以从那里继续。

我更新了代码以处理该方案,现在问题已解决。

答案 2 :(得分:0)

我有这个问题,我的情况可能非常具体,但无论如何我都会分享我的经验。

这里的要点是应用程序只在生产中崩溃,因此它只会在生产中被解雇,这会破坏构建。在我们的案例中,罪魁祸首是React's dependencies中的一个缩小。

要带走的东西:

  1. 密切关注您的依赖项的任何更新
  2. 使用崩溃日志