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
奇舞週刊

相關文章
相關標籤/搜索