iOS之查看及导出项目运行日志

前文:
最近笔者在家远程办公的时候,在测试项目时,遇到了测试同学测试出了问题,但是笔者这边不能复现的情况。所以整理了一下 iOS 查看及导出项目运行日志。如大家有需要,可以继续查看详情。

一、控制台查看日志

iPhone 连接 Mac 的情况下使用控制台, 搜索项目名称,笔者这里的项目名称为 QiLogTool ,找出相应的日志。此时不管是否正在使用 Xcode 在运行项目,在控制台中都能查看到 iPhone 中的日志。

二、重定向NSLog日志

注:NSLog 重定向后,控制台就不会打印日志了。

使用如下代码可以把 NSLog 日志,重定向到指定的文件目录中。

+ (void)redirectNSLog {
    NSString *fileName = @"NSLog.log";
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentDirectory = paths.firstObject;
    NSString *saveFilePath = [documentDirectory stringByAppendingPathComponent:fileName];
    // 先删除已经存在的文件
    NSFileManager *defaultManager = [NSFileManager defaultManager];
    [defaultManager removeItemAtPath:saveFilePath error:nil];

    // 将log输入到文件
    freopen([saveFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stdout);
    freopen([saveFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr);
}

freopen是被包含于C标准库头文件<stdio.h>中的一个函数,用于重定向输入输出流。该函数可以在不改变代码原貌的情况下改变输入输出环境,但使用时应当保证流是可靠的。

FILE    *freopen(
    const char * __restrict,
    const char * __restrict, 
    FILE * __restrict)
    __DARWIN_ALIAS(freopen);

形参说明:
filename:需要重定向到的文件名或文件路径。
mode:代表文件访问权限的字符串。例如,"r"表示"只读访问""w"表示"只写访问""a"表示"追加写入"。
stream:需要被重定向的文件流。

下图是笔者把 NSLog 的内容重定向输出到 NSLog.log 之后的截图。

三、通过 Xcode下载 Container 查看日志

通过Xcode 中的container 部分获取日志

下图是笔者在官方文档截图的沙盒目录。

下方的截图依次是笔者通过 Xcode 获取安装包中的沙盒文件的截图。

四、通过 PAirSandbox 查看 Documents 中的内容

使用 PAirSandbox:AirSandbox,从手机屏幕右侧边缘,左滑手势可以触发显示查看当前沙盒中的内容的window。并且可以通过三方软件把沙盒中的内容分享给其他人。点击右上角的 Close 关闭按钮即可关闭沙盒目录界面。

#ifdef DEBUG
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
          [[PAirSandbox sharedInstance] enableSwipe];
      });
#endif

效果示意图如下:

 

 

五、通过 文件 App 查看 Documents 中的日志文件

需要在 Info.plist 文件中配置如下内容,便可实时在文件 App 中查看沙盒中的文件内容。

设置 Application supports iTunes file sharingYES。 设置 Supports opening documents in placeYES

设置的示意图如下:

 

通过文件 App 实时查看日志的效果示意图如下。

 

六、自定义捕获普通日志及崩溃日志等

1. 对可能出现崩溃的代码进行 try catch 处理

/**
    * 普通异常的捕获方式:
    * 2020-03-25 10:47:11.179085+0800 QiLogTool[18371:4064396] exception:***
    * -[__NSSingleObjectArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 0]
    * 2020-03-25 10:47:11.179310+0800 QiLogTool[18371:4064396] finally
*/
@try {
    NSArray *arr = @[@(1)];
    arr[2];
} @catch (NSException *exception) {
    NSLog(@"exception:%@", exception);
} @finally {
    NSLog(@"finally");
}

如果项目中可能出现异常的地方比较多,使用try catch的方式可能会比较繁琐。那么可以考虑使用捕获项目全局异常的方式。

2. 使用全局捕获异常的方式处理异常

下方的代码可以查看异常情况,并且记录下来日志,在用户侧,可实现可把崩溃日志上传到服务端,进行日志分析的操作。不过 App 遇到异常依然会闪退。

#ifdef DEBUG
    // 捕获异常 Summary Changes the top-level error handler.
    NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
#endif
#pragma mark - 捕获异常 不防崩
void UncaughtExceptionHandler(NSException *exception) {
    // 获取异常崩溃信息
    NSArray *callStack = [exception callStackSymbols];
    NSString *reason = [exception reason];
    NSString *name = [exception name];
    NSString *crashDetail = [NSString stringWithFormat:@"========异常错误报告========\n name:%@\n reason:\n%@\n callStackSymbols:\n%@", name, reason, [callStack componentsJoinedByString:@"\n"]];
    NSLog(@"%@", crashDetail);
    [QiLogTool logFile:@"crash.log" content:crashDetail];
}

3. 出现崩溃后使用 RunLoop 保证 App 仍然继续运行一次

首先感谢 RunLoop总结:RunLoop的应用场景(五)

QiLogTool 中也有相关的代码。大家有兴趣的话,可以自行下载查看。

捕获异常部分的代码,和笔者在上文中第2步中提到的全局捕获异常的方式类似。可以多了解一下的还有,出现了异常的情况下,我们可以记录日志,并且使用 RunLoop 相关代码保持应用在第一次遇到异常的时候不崩溃。

RunLoop处理遇到异常,保持App 仍然可以继续运行一次的主要代码为:

// 获取到当前线程的的CFRunLoop对象及 获取包含特定CFRunLoop对象的Modes数组 在指定的Modes中运行当前线程的CFRunLoop对象
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);    
while (!ignore) {
     for (NSString *mode in (__bridge NSArray *)allModes) {
        // Runs the current thread’s CFRunLoop object in a particular mode.
        CFRunLoopRunInMode((CFStringRef)mode, 0.001, false);
     }
}    
CFRelease(allModes);

4. 其他查看 Crash 日志的方法

4.1 Mac 路径下查看

通过如下方式查看崩溃日志不准确。

~/Library/Logs/CrashReporter/MobileDevice
4.2 使用 Xcode 查看崩溃日志的其他方式

上边的红色箭头的1,2可以用于查看设备端通过 Xcode 安装的项目的日志;

下边的蓝色箭头的1,2可以用于查看上传到 AppStore 项目的 Crash 的日志。

 

4.3 使用其他的三方查看线上崩溃日志

七、QiLogTool Demo地址、使用方式及效果演示

1. QiLogTool Demo地址

QiLogTool

2. QiLogTool 使用方式:

把 CrashHandler 和 AirSandBox 及 QiLogTool 的文件夹中的文件都添加到自己的项目中。 在应用启动的时候调用如下代码:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    if (@available(iOS 13.0, *)) {
        
    } else {
        self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        self.window.backgroundColor = [UIColor whiteColor];
        self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[ViewController new]];
        [self.window makeKeyAndVisible];
    }
    // 是否要直接访问沙盒中的内容
    #ifdef DEBUG
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [[PAirSandbox sharedInstance] enableSwipe];
        });
    #endif
    
    // 重定向NSLog内容 注意:把NSLog的内容重定向到其他文件后 控制台就不会再输出内容
    [QiLogTool redirectNSLog];
    
    #ifdef DEBUG
        // 捕获异常 Changes the top-level error handler.
         NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
    #endif
    
    // #ifdef DEBUG
    #ifdef RELEASE
        // 捕获异常并且有一次应用遇到异常后 不会闪退的处理
        [CrashHandler sharedInstance];
    #endif
    return YES;
}

#pragma mark - 捕获异常 不防崩
void UncaughtExceptionHandler(NSException *exception) {
    // 获取异常崩溃信息
    NSArray *callStack = [exception callStackSymbols];
    NSString *reason = [exception reason];
    NSString *name = [exception name];
    NSString *crashDetail = [NSString stringWithFormat:@"========异常错误报告========\n name:%@\n reason:\n%@\n callStackSymbols:\n%@", name, reason, [callStack componentsJoinedByString:@"\n"]];
    NSLog(@"%@", crashDetail);
    [QiLogTool logFile:@"crash.log" content:crashDetail];
    // 记录日志后 可以选择合适的时机把日志上传到服务端 上传成功后 把相应的日志删除即可
}

3. QiLogTool 使用效果演示:

笔者下边的演示在应用启动时调用的代码为:

// 是否要直接访问沙盒中的内容
#ifdef DEBUG
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [[PAirSandbox sharedInstance] enableSwipe];
    });
#endif
    
// 重定向NSLog内容 注意:把NSLog的内容重定向到其他文件后 控制台就不会再输出内容
[QiLogTool redirectNSLog];
    
#ifdef DEBUG
// #ifdef RELEASE
// 捕获异常并且有一次应用遇到异常后 不会闪退的处理
[CrashHandler sharedInstance];
#endif

下图中点击屏幕中间的测试日志按钮后,会调用的方法如下:

- (void)logTest {
    NSLog(@"NSLog日志内容");
    // 测试日志工具
    [QiLogTool logFile:@"logfile.log" content:[NSString stringWithFormat:@"时间:%@\n内容:%@\n", [[NSDate date] dateByAddingTimeInterval:8.0 * 60 * 60], @"logContent"]];
    // 测试崩溃 记录日志效果
    NSArray *arr = @[@(1)];
    NSLog(@"arr[2]:%@", arr[2]);
}

因笔者录制的 gif 图较大,直接上传受限。如需查看使用过程中的效果图可点击下方链接 QiLogTool使用效果图

posted on 2022-09-28 16:40  梁飞宇  阅读(1781)  评论(0)    收藏  举报