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

级别:★☆☆☆☆
标签:「iOS 查看及导出项目运行日志」「iOS 查看日志」「iOS 查看崩溃日志」
做者: WYW
审校: QiShare团队php


前文:
最近笔者在家远程办公的时候,在测试项目时,遇到了测试同窗测试出了问题,可是笔者这边不能复现的状况。因此整理了一下 iOS 查看及导出项目运行日志。如你们有须要,能够继续查看详情。html

笔者将分享iOS 查看及导出项目运行日志的内容,全文分为以下7个部分。git

  1. 控制台查看日志;
  2. 重定向 NSLog 日志;
  3. 经过 Xcode下载 Container 查看日志;
  4. 经过 PAirSandbox:AirSandbox 查看 Documents 中的内容;
  5. 经过 文件 App 查看 Documents 中的日志文件;
  6. 自定义捕获普通日志及崩溃日志等;
  7. QiLogTool Demo地址、使用方式及效果演示。

1、控制台查看日志

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

控制台查看日志

2、重定向NSLog日志

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

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

+ (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>中的一个函数,用于重定向输入输出流。该函数能够在不改变代码原貌的状况下改变输入输出环境,但使用时应当保证流是可靠的。微信

引自360百科:freopenapp

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

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

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

NSLog 重定向

3、经过 Xcode下载 Container 查看日志

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

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

沙盒文件示意

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

Xcode 沙盒文件1

Xcode 沙盒文件2

Xcode 沙盒文件3

Xcode 沙盒文件4

Xcode 沙盒文件5

4、经过 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
复制代码

效果示意图以下:

PAirSandbox1

PAirSandbox2

PAirSandbox3

5、经过 文件 App 查看 Documents 中的日志文件

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

设置 Application supports iTunes file sharing 为YES。 设置 Supports opening documents in place 为 YES。

设置的示意图以下:

File App1

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

File App2

File App3

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

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
复制代码

otherSearchCrashStyle1

4.2 使用 Xcode 查看崩溃日志的其余方式

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

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

otherSearchCrashStyle2

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

7、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使用效果图

参考学习网址

File System Programming Guide
iOS 将NSLog日志重定向输出到文件中保存
iOS崩溃异常的处理
RunLoop总结:RunLoop的应用场景(五)


了解更多iOS及相关新技术,请关注咱们的公众号:

小编微信:可加并拉入《QiShare技术交流群》。

关注咱们的途径有:
QiShare(简书)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公众号)

推荐文章:
Flutter Platform Channel 使用与源码分析
开发没切图怎么办?矢量图标(iconFont)上手指南
DarkMode、WKWebView、苹果登陆是否必须适配?
iOS 接入 Google、Facebook 登陆(二)
iOS 接入 Google、Facebook 登陆(一)
Nginx 入门实战 iOS中的3D变换(二)
iOS中的3D变换(一)
WebSocket 双端实践(iOS/ Golang)
今天咱们来聊一聊WebSocket(iOS/Golang)
奇舞团安卓团队——aTaller
奇舞周刊

相关文章
相关标签/搜索