如何捕獲app閃退的原因?如何將閃退的原因發送到服務器?
一、異常處理:預先設置捕獲的異常和未知異常。
預先設置捕獲的異常的處理
該種異常是通過標準的@try @catch(id exception) @finally 來處理的。
@try {
// 有可能出現異常的代碼塊,可以創建異常對象并且手動拋出異常或者在執行可能出現的代碼會自動觸發并拋出異常
} @catch (id exception) // 大部分情況下是通過直接指定異常參數@catch(NSException *e)
{
// 捕獲到異常的處理措施
} @finally {
// 無論有無異常都要執行的操作,例如某些資源的釋放等。
}
對于@try代碼塊中出現的異常,會將異常發送到@catch代碼塊中進行處理。在這種情況下出現的異常情況,不會將異常發送到系統級別,因此不會引起系統的閃退情況。
接下來寫代碼測試
捕捉閃退信息如下:
預先設置對異常的捕獲,不會引起app的閃退。沒有對可能發生異常的地方進行處理機制,會引起app的閃退。
二、未知異常的捕獲
在默認情況下,系統發生了未知異常,系統會捕獲該異常并且退出app。發生異常后,系統會創建一個NSExcetion對象,并且在異常出拋出,等待有接受者,若沒有傳遞給系統處理。那么如何來獲取這個未知異常呢?該問題問的好!利用如下函數來解決這個問題:
FOUNDATION_EXPORT void NSSetUncaughtExceptionHandler(NSUncaughtExceptionHandler * _Nullable);
該函數是一個全局的函數,該函數一般在app開始的時候調用,該函數的意義:設置未知異常的捕獲函數,參數是未知異常處理函數的函數名,該未知異常處理函數的模式如下:
typedef void NSUncaughtExceptionHandler(NSException *exception);
未知異常處理函數的示例
void uncaughtExceptionHandler(NSException *exception) {
// 在app退出前的一些處理任務,系統會等待該函數的執行完畢
NSLog(@"CRASH: %@", exception);
NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
NSLog(@"處理crashing ~~~~~~~~~~ !");
sleep(10);
NSLog(@"處理crashing end~~~~~~~~~~ !");
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
return YES;
}
備注:在app退出前的一些處理任務,系統會等待該函數的執行完畢,上面代碼中我們進行了線程 sleep(10)來進行測試,收到異常后程序是否立即退出,也就是收到異常后能否立即將閃退日志信息上傳到服務端。
接下來代碼測試結果如下:
2021-03-29 15:45:42.915127+0800 PodLoad[61855:2325664] CRASH: *** -[__NSArrayM insertObject:atIndex:]: object cannot be nil
2021-03-29 15:45:42.915467+0800 PodLoad[61855:2325664] Stack Trace: (
0 CoreFoundation 0x00007fff20421af6 __exceptionPreprocess + 242
1 libobjc.A.dylib 0x00007fff20177e78 objc_exception_throw + 48
2 CoreFoundation 0x00007fff2049e77f _CFThrowFormattedException + 194
3 CoreFoundation 0x00007fff2049c656 -[__NSArrayM insertObject:atIndex:].cold.2 + 0
4 CoreFoundation 0x00007fff2031f678 -[__NSArrayM insertObject:atIndex:] + 1134
5 PodLoad 0x0000000103918c23 -[ViewController touchesBegan:withEvent:] + 115
6 UIKitCore 0x00007fff246ca70f forwardTouchMethod + 321
7 UIKitCore 0x00007fff246ca5bd -[UIResponder touchesBegan:withEvent:] + 49
8 UIKitCore 0x00007fff246d95b5 -[UIWindow _sendTouchesForEvent:] + 622
9 UIKitCore 0x00007fff246db6c7 -[UIWindow sendEvent:] + 4774
10 UIKitCore 0x00007fff246b5466 -[UIApplication sendEvent:] + 633
11 UIKitCore 0x00007fff24745f04 __processEventQueue + 13895
12 UIKitCore 0x00007fff2473c877 __eventFetcherSourceCallback + 104
13 CoreFoundation 0x00007fff2039038a __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
14 CoreFoundation 0x00007fff20390282 __CFRunLoopDoSource0 + 180
15 CoreFoundation 0x00007fff2038f764 __CFRunLoopDoSources0 + 248
16 CoreFoundation 0x00007fff20389f2f __CFRunLoopRun + 878
17 CoreFoundation 0x00007fff203896d6 CFRunLoopRunSpecific + 567
18 GraphicsServices 0x00007fff2c257db3 GSEventRunModal + 139
19 UIKitCore 0x00007fff24696cf7 -[UIApplication _run] + 912
20 UIKitCore 0x00007fff2469bba8 UIApplicationMain + 101
21 PodLoad 0x0000000103918fb2 main + 114
22 libdyld.dylib 0x00007fff2025a3e9 start + 1
23 ??? 0x0000000000000001 0x0 + 1
)
2021-03-29 15:45:42.917124+0800 PodLoad[61855:2325664] 處理crashing ~~~~~~~~~~ !
2021-03-29 15:45:52.918737+0800 PodLoad[61855:2325664] 處理crashing end~~~~~~~~~~ !
2021-03-29 15:45:52.919067+0800 PodLoad[61855:2325664] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff20421af6 __exceptionPreprocess + 242
1 libobjc.A.dylib 0x00007fff20177e78 objc_exception_throw + 48
2 CoreFoundation 0x00007fff2049e77f _CFThrowFormattedException + 194
3 CoreFoundation 0x00007fff2049c656 -[__NSArrayM insertObject:atIndex:].cold.2 + 0
4 CoreFoundation 0x00007fff2031f678 -[__NSArrayM insertObject:atIndex:] + 1134
5 PodLoad 0x0000000103918c23 -[ViewController touchesBegan:withEvent:] + 115
6 UIKitCore 0x00007fff246ca70f forwardTouchMethod + 321
7 UIKitCore 0x00007fff246ca5bd -[UIResponder touchesBegan:withEvent:] + 49
8 UIKitCore 0x00007fff246d95b5 -[UIWindow _sendTouchesForEvent:] + 622
9 UIKitCore 0x00007fff246db6c7 -[UIWindow sendEvent:] + 4774
10 UIKitCore 0x00007fff246b5466 -[UIApplication sendEvent:] + 633
11 UIKitCore 0x00007fff24745f04 __processEventQueue + 13895
12 UIKitCore 0x00007fff2473c877 __eventFetcherSourceCallback + 104
13 CoreFoundation 0x00007fff2039038a __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
14 CoreFoundation 0x00007fff20390282 __CFRunLoopDoSource0 + 180
15 CoreFoundation 0x00007fff2038f764 __CFRunLoopDoSources0 + 248
16 CoreFoundation 0x00007fff20389f2f __CFRunLoopRun + 878
17 CoreFoundation 0x00007fff203896d6 CFRunLoopRunSpecific + 567
18 GraphicsServices 0x00007fff2c257db3 GSEventRunModal + 139
19 UIKitCore 0x00007fff24696cf7 -[UIApplication _run] + 912
20 UIKitCore 0x00007fff2469bba8 UIApplicationMain + 101
21 PodLoad 0x0000000103918fb2 main + 114
22 libdyld.dylib 0x00007fff2025a3e9 start + 1
23 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
terminating with uncaught exception of type NSException
可見sleep(10)結束之后才結束APP
日志信息上傳
關鍵是需要進行同步操作,使得閃退日志上傳成功后再結束APP進程。
比較成熟的第三方閃退監控平臺:Bugly、友盟等