Ios 在生产中反应自然破碎

Ios 在生产中反应自然破碎,ios,xcode,react-native,Ios,Xcode,React Native,我们使用React Native构建了一个应用程序,以改进UX和以前Cordova应用程序的功能 一切都很顺利。几个月的开发、QA、应用程序审查,然后我们发布到应用程序商店。它适用于我们尝试的所有设备,从iPhone4S到iPhone6S+,我们在iOS8.3(最早可以通过xCode下载的模拟器)到10.0上进行了测试 发布后,许多用户开始报告应用程序在启动屏幕消失之前崩溃。我们以前在应用程序审查、测试或其他任何地方都没有见过这种行为 我们调查了xCode中的“崩溃”,它们显然没有出现,因为数百

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

一切都很顺利。几个月的开发、QA、应用程序审查,然后我们发布到应用程序商店。它适用于我们尝试的所有设备,从iPhone4S到iPhone6S+,我们在iOS8.3(最早可以通过xCode下载的模拟器)到10.0上进行了测试

发布后,许多用户开始报告应用程序在启动屏幕消失之前崩溃。我们以前在应用程序审查、测试或其他任何地方都没有见过这种行为

我们调查了xCode中的“崩溃”,它们显然没有出现,因为数百名用户经历了崩溃,而我们只能看到很少的崩溃——这似乎与启动无关

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

你知道我下一步该去哪里吗?我们真的不想回到旧版本,失去几个月的工作


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

当似乎没有任何其他分析途径时,我求助于简单的日志记录

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

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

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

    • 在应用程序代理的
      应用程序中的早期“StartupStart”:didFinishLaunchingWithOptions:
    • 视图末尾的“startupCompleted”控制器的
      视图显示
      (而不是
      视图显示
      !在发送这两个视图时,可能会出现很多错误)
    另外,我以前的日志重定向和旋转方法是这样的(Objective-C):

    -(无效)日志重定向{
    //如果stderr不去XCode控制台(然后在生产中运行)
    如果(!isatty(标准文件号)){
    //轮换原木
    int旋转计数=3;
    NSMutableArray*logRotations=[NSMutableArray];
    对于(int i=0;i<旋转计数;i++){
    [logRotations addObject:[pathToLogsDir stringByAppendingPathComponent:[NSString stringWithFormat:@“appnameorbundleid.%d.log”,i]];
    }
    [[NSFileManager defaultManager]removeItemAtPath:[logRotations lastObject]错误:nil];
    对于(int i=旋转计数-1;i>0;i--){
    [[
    
    - (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);
        }
    }