級別:★☆☆☆☆
標籤:「iOS 檢視及匯出專案執行日誌」「iOS 檢視日誌」「iOS 檢視崩潰日誌」
作者: WYW
審校: QiShare團隊
前文:
最近筆者在家遠端辦公的時候,在測試專案時,遇到了測試同學測試出了問題,但是筆者這邊不能復現的情況。所以整理了一下 iOS 檢視及匯出專案執行日誌。如大家有需要,可以繼續檢視詳情。
筆者將分享iOS 檢視及匯出專案執行日誌的內容,全文分為如下7個部分。
- 控制檯檢視日誌;
- 重定向 NSLog 日誌;
- 通過 Xcode下載 Container 檢視日誌;
- 通過 PAirSandbox:AirSandbox 檢視 Documents 中的內容;
- 通過 檔案 App 檢視 Documents 中的日誌檔案;
- 自定義捕獲普通日誌及崩潰日誌等;
- 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 之後的截圖。
三、通過 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 sharing
為YES。
設定 Supports opening documents in place
為 YES。
設定的示意圖如下:
通過檔案 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地址
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
奇舞週刊