From 22344d2d41b736bf7335aa5068d3b014a6100980 Mon Sep 17 00:00:00 2001 From: wux Date: Thu, 31 Oct 2019 15:46:34 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20ios=20=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin.xml | 18 ++-- src/ios/CrashHandler.h | 12 +++ src/ios/CrashHandler.m | 181 +++++++++++++++++++++++++++++++++++++++ src/ios/CrashLogPlugin.h | 5 ++ src/ios/CrashLogPlugin.m | 12 +++ 5 files changed, 223 insertions(+), 5 deletions(-) create mode 100644 src/ios/CrashHandler.h create mode 100644 src/ios/CrashHandler.m create mode 100644 src/ios/CrashLogPlugin.h create mode 100644 src/ios/CrashLogPlugin.m diff --git a/plugin.xml b/plugin.xml index 0b208f2..18948f2 100644 --- a/plugin.xml +++ b/plugin.xml @@ -3,9 +3,6 @@ xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android"> CrashLog - @@ -13,11 +10,22 @@ - + - + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ios/CrashHandler.h b/src/ios/CrashHandler.h new file mode 100644 index 0000000..94c19c5 --- /dev/null +++ b/src/ios/CrashHandler.h @@ -0,0 +1,12 @@ +#import + +@interface CrashHandler : NSObject { + BOOL dismissed; +} + +@end + +void HandleException(NSException *exception); +void SignalHandler(int signal); + +void RegistUncauthExceptionHandler(void); diff --git a/src/ios/CrashHandler.m b/src/ios/CrashHandler.m new file mode 100644 index 0000000..4d2f005 --- /dev/null +++ b/src/ios/CrashHandler.m @@ -0,0 +1,181 @@ +#import "CrashHandler.h" +//#include +#include + +NSString * const UncaughtExceptionHandlerSignalExceptionName = @"UncaughtExceptionHandlerSignalExceptionName"; +NSString * const UncaughtExceptionHandlerSignalKey = @"UncaughtExceptionHandlerSignalKey"; +NSString * const UncaughtExceptionHandlerAddressesKey = @"UncaughtExceptionHandlerAddressesKey"; + +//volatile int32_t UncaughtExceptionCount = 0; +//const int32_t UncaughtExceptionMaximum = 10; + +const NSInteger UncaughtExceptionHandlerSkipAddressCount = 4; +const NSInteger UncaughtExceptionHandlerReportAddressCount = 5; + +@implementation CrashHandler + +NSDateFormatter *dateFormatter; + ++ (NSArray *)backtrace { + void* callstack[128]; + int frames = backtrace(callstack, 128); + char **strs = backtrace_symbols(callstack, frames); + + int i; + NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames]; + for ( + i = UncaughtExceptionHandlerSkipAddressCount; + i < UncaughtExceptionHandlerSkipAddressCount + + UncaughtExceptionHandlerReportAddressCount; + i++) + { + [backtrace addObject:[NSString stringWithUTF8String:strs[i]]]; + } + free(strs); + + return backtrace; +} + ++ (NSString *)applicationDocumentsDirectory { + return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; +} + ++ (NSString *)filename { + NSString * date = [dateFormatter stringFromDate:[NSDate date]]; + long timeStamp = (long)(NSTimeInterval)([[NSDate date] timeIntervalSince1970]); + return [NSString stringWithFormat:@"crash-%@-%ld.log", date, timeStamp]; +} + +- (void)handleException:(NSException *)exception { + NSLog(@" 崩溃 handleException ================================== "); + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"错误" message:@"很抱歉,程序出现异常,即将退出." preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *sure =[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + dismissed = YES; + }]; + + [alertController addAction:sure]; + + id rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController; + if([rootViewController isKindOfClass:[UINavigationController class]]) + { + rootViewController = ((UINavigationController *)rootViewController).viewControllers.firstObject; + } + if([rootViewController isKindOfClass:[UITabBarController class]]) + { + rootViewController = ((UITabBarController *)rootViewController).selectedViewController; + } + + [rootViewController presentViewController:alertController animated:YES completion:nil]; + + CFRunLoopRef runLoop = CFRunLoopGetCurrent(); + CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop); + + while (!dismissed) { + for (NSString *mode in (__bridge NSArray *)allModes) { + CFRunLoopRunInMode((CFStringRef)mode, 0.001, false); + } + } + + CFRelease(allModes); + + [self saveLog:exception]; + NSSetUncaughtExceptionHandler(NULL); + + signal(SIGABRT, SIG_DFL); + signal(SIGILL, SIG_DFL); + signal(SIGSEGV, SIG_DFL); + signal(SIGFPE, SIG_DFL); + signal(SIGBUS, SIG_DFL); + signal(SIGPIPE, SIG_DFL); + + if ([[exception name] isEqual:UncaughtExceptionHandlerSignalExceptionName]) + { + kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]); + } + else + { + [exception raise]; + } +} + +- (void)saveLog:(NSException *)exception { + NSLog(@"崩溃日志文件=================================="); + NSArray * arr = [exception callStackSymbols]; + NSString * reason = [exception reason]; // // 崩溃的原因 可以有崩溃的原因(数组越界,字典nil,调用未知方法...) + NSString * name = [exception name]; + NSString * url = [NSString stringWithFormat:@"exception:%@\nreason:\n%@\ncallStackSymbols:\n%@",name,reason,[arr componentsJoinedByString:@"\n"]]; + NSString * path = [[CrashHandler applicationDocumentsDirectory] stringByAppendingPathComponent:[CrashHandler filename]]; + NSLog(@"崩溃日志文件:%@", path); + [url writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil]; +} + +@end + +void HandleException(NSException *exception) { +// int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount); +// if (exceptionCount > UncaughtExceptionMaximum) { +// return; +// } + + NSArray *callStack = [CrashHandler backtrace]; + NSMutableDictionary *userInfo = + [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]]; + [userInfo + setObject:callStack + forKey:UncaughtExceptionHandlerAddressesKey]; + + [[[CrashHandler alloc] init] + performSelectorOnMainThread:@selector(handleException:) + withObject: + [NSException + exceptionWithName:[exception name] + reason:[exception reason] + userInfo:userInfo] + waitUntilDone:YES]; +} + +void SignalHandler(int signal) { +// int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount); +// if (exceptionCount > UncaughtExceptionMaximum) { +// return; +// } + + NSMutableDictionary *userInfo = + [NSMutableDictionary + dictionaryWithObject:[NSNumber numberWithInt:signal] + forKey:UncaughtExceptionHandlerSignalKey]; + + NSArray *callStack = [CrashHandler backtrace]; + [userInfo + setObject:callStack + forKey:UncaughtExceptionHandlerAddressesKey]; + + [[[CrashHandler alloc] init] + performSelectorOnMainThread:@selector(handleException:) + withObject: + [NSException + exceptionWithName:UncaughtExceptionHandlerSignalExceptionName + reason: + [NSString stringWithFormat: + NSLocalizedString(@"Signal %d was raised.", nil), + signal] + userInfo: + [NSDictionary + dictionaryWithObject:[NSNumber numberWithInt:signal] + forKey:UncaughtExceptionHandlerSignalKey]] + waitUntilDone:YES]; +} + +void RegistUncauthExceptionHandler(void) { + NSLog(@"崩溃日志文件============ install ======================"); + dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"yyyy-MM-dd-HH-mm-ss"]; + NSSetUncaughtExceptionHandler(&HandleException); + signal(SIGABRT, SignalHandler); + signal(SIGILL, SignalHandler); + signal(SIGSEGV, SignalHandler); + signal(SIGFPE, SignalHandler); + signal(SIGBUS, SignalHandler); + signal(SIGPIPE, SignalHandler); +} diff --git a/src/ios/CrashLogPlugin.h b/src/ios/CrashLogPlugin.h new file mode 100644 index 0000000..4cc942d --- /dev/null +++ b/src/ios/CrashLogPlugin.h @@ -0,0 +1,5 @@ +#import + +@interface CrashLogPlugin : CDVPlugin + +@end diff --git a/src/ios/CrashLogPlugin.m b/src/ios/CrashLogPlugin.m new file mode 100644 index 0000000..de1fec8 --- /dev/null +++ b/src/ios/CrashLogPlugin.m @@ -0,0 +1,12 @@ +#import "CrashHandler.h" +#import "CrashLogPlugin.h" + +@implementation CrashLogPlugin + +- (void)pluginInitialize +{ + NSLog(@"崩溃日志文件:pluginInitialize"); + RegistUncauthExceptionHandler(); +} + +@end