iOS 檢視及匯出專案執行日誌

QiShare發表於2020-03-26

級別:★☆☆☆☆
標籤:「iOS 檢視及匯出專案執行日誌」「iOS 檢視日誌」「iOS 檢視崩潰日誌」
作者: WYW
審校: QiShare團隊


前文:
最近筆者在家遠端辦公的時候,在測試專案時,遇到了測試同學測試出了問題,但是筆者這邊不能復現的情況。所以整理了一下 iOS 檢視及匯出專案執行日誌。如大家有需要,可以繼續檢視詳情。

筆者將分享iOS 檢視及匯出專案執行日誌的內容,全文分為如下7個部分。

  1. 控制檯檢視日誌;
  2. 重定向 NSLog 日誌;
  3. 通過 Xcode下載 Container 檢視日誌;
  4. 通過 PAirSandbox:AirSandbox 檢視 Documents 中的內容;
  5. 通過 檔案 App 檢視 Documents 中的日誌檔案;
  6. 自定義捕獲普通日誌及崩潰日誌等;
  7. QiLogTool Demo地址、使用方式及效果演示。

一、控制檯檢視日誌

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>中的一個函式,用於重定向輸入輸出流。該函式可以在不改變程式碼原貌的情況下改變輸入輸出環境,但使用時應當保證流是可靠的。

引自360百科:freopen

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

形參說明:
filename:需要重定向到的檔名或檔案路徑。
mode:代表檔案訪問許可權的字串。例如,"r"表示"只讀訪問""w"表示"只寫訪問""a"表示"追加寫入"。
stream:需要被重定向的檔案流。
複製程式碼

下圖是筆者把 NSLog 的內容重定向輸出到 NSLog.log 之後的截圖。

NSLog 重定向

三、通過 Xcode下載 Container 檢視日誌

通過Xcode 中的container 部分獲取日誌

下圖是筆者在官方文件截圖的沙盒目錄。

沙盒檔案示意

下方的截圖依次是筆者通過 Xcode 獲取安裝包中的沙盒檔案的截圖。

Xcode 沙盒檔案1

Xcode 沙盒檔案2

Xcode 沙盒檔案3

Xcode 沙盒檔案4

Xcode 沙盒檔案5

四、通過 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

五、通過 檔案 App 檢視 Documents 中的日誌檔案

需要在 Info.plist 檔案中配置如下內容,便可實時在檔案 App 中檢視沙盒中的檔案內容。

設定 Application supports iTunes file sharing 為YES。 設定 Supports opening documents in place 為 YES。

設定的示意圖如下:

File App1

通過檔案 App 實時檢視日誌的效果示意圖如下。

File App2

File App3

六、自定義捕獲普通日誌及崩潰日誌等

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 使用其他的三方檢視線上崩潰日誌

七、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及相關新技術,請關注我們的公眾號:

iOS 檢視及匯出專案執行日誌

小編微信:可加並拉入《QiShare技術交流群》。

iOS 檢視及匯出專案執行日誌

關注我們的途徑有:
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
奇舞週刊

相關文章