釋出的app難免會出現一些奇葩的bug,為了能夠實時跟蹤app的崩潰,需要接管系統的異常捕獲介面,自己來收集儲存崩潰現場資訊。
下面簡單說一下幾個平臺的異常崩潰捕獲。
1.iOS
1.1 Exception
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
-(BOOL)install{ if(NSGetUncaughtExceptionHandler() != custom_exceptionHandler) oldhandler = NSGetUncaughtExceptionHandler(); if(self->_handlerEnable){ NSSetUncaughtExceptionHandler(&custom_exceptionHandler); }else{ DDLogWarning(@"NSEXception handler disable"); } return YES; } -(BOOL)uninstall{ NSSetUncaughtExceptionHandler(oldhandler); return YES; } |
1.2 Signal
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
-(BOOL)install{ if(installed){ DDLogError(@"signal handler has been installed"); return NO; } custom_crash_stk.ss_size = MAX(MINSIGSTKSZ, 64*1024); custom_crash_stk.ss_sp = malloc(custom_crash_stk.ss_size); custom_crash_stk.ss_flags = 0; if(custom_crash_stk.ss_sp == NULL){ return NO; } //替換訊號處理函式棧,避免棧已經耗盡,導致程式退出 if(sigaltstack(&custom_crash_stk, 0) < 0) return NO; if(!sa_preHandlers){ sa_preHandlers = (struct sigaction*)malloc(sizeof(struct sigaction) * monitored_signals_count); memset(sa_preHandlers, 0, sizeof(struct sigaction) * monitored_signals_count); } struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_SIGINFO | SA_ONSTACK; sigemptyset(&sa.sa_mask); sa.sa_sigaction = &custom_signalHandler; for (int i = 0; i < monitored_signals_count; i++) { if(sigaction(monitored_signals[i], &sa, (struct sigaction*)(sa_preHandlers+i)) != 0){ DDLogError(@"install signalHandler failed, uninstall it!"); [self uninstall]; return NO; } } installed = 1; return YES; } -(BOOL)uninstall{ if(installed){ if(custom_crash_stk.ss_sp){ free(custom_crash_stk.ss_sp); custom_crash_stk.ss_sp = nil; } for (int i = 0; i < monitored_signals_count; i++) { if(sigaction(monitored_signals[i], (struct sigaction*)(sa_preHandlers+i), 0) != 0){ return NO; } } if(sa_preHandlers) free(sa_preHandlers); installed = 0; return YES; }else{ DDLogError(@"signalHandler already uninstalled!"); return NO; } } |
2.Cocos
2.1 Cocos-Lua
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
local function handleLuaException(msg) if msg==nil then return end local targetPlatform = cc.Application:getInstance():getTargetPlatform() local supportObjectCBridge = false if (cc.PLATFORM_OS_IPHONE == targetPlatform) or (cc.PLATFORM_OS_IPAD == targetPlatform) or (cc.PLATFORM_OS_MAC == targetPlatform) then supportObjectCBridge = true end local supportJavaBridge = false if (cc.PLATFORM_OS_ANDROID == targetPlatform) then supportJavaBridge = true end if (supportJavaBridge == true) then //... elseif (supportObjectCBridge == true) then //... end end function __G__TRACKBACK__(msg) handleLuaException(msg) return msg end |
2.2 Cocos-JS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//註冊異常處理回撥函式 void JSExceptionHandler::registerJSExceptionHandler(JSContext *cx) { JS_SetErrorReporter(cx, JSExceptionHandler::reportError); } void JSExceptionHandler::reportError(JSContext *cx, const char *message, JSErrorReport *report) { const char* format = "%s:%u:%s\n"; const char* fileName = report->filename ? report->filename : "no filename"; int bufLen = strlen(format) + strlen(fileName) + strlen(message) + 16; char* traceback = (char*)malloc(bufLen); memset(traceback, 0, bufLen); sprintf(traceback, format, fileName, (unsigned int) report->lineno, message); //.... free(traceback); }; |
3.U3D
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//註冊未處理異常回撥 System.AppDomain.CurrentDomain.UnhandledException += _OnUnhandledExceptionHandler; //註冊日誌回撥 Application.RegisterLogCallback(_OnLogCallbackHandler); static private void _OnLogCallbackHandler(string name, string stack, LogType type) { //… } private static void _OnUnhandledExceptionHandler(object sender, System.UnhandledExceptionEventArgs args) { if (args.ExceptionObject.GetType() == typeof(System.Exception)) { //… } } |