美文网首页
iOS 复活崩溃应用及崩溃信息上报

iOS 复活崩溃应用及崩溃信息上报

作者: 起床赚钱了 | 来源:发表于2023-02-12 17:57 被阅读0次

    一、Appdelagte中注册crash记录上报

    #import "CrashHandler.h"
    -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
      // Override point for customization after application launch.
      [CrashHandler sharedInstance];
      return YES;
    }
    

    二、CrashHandler文件

    #import <Foundation/Foundation.h>
     @interface CrashHandler : NSObject
    {
      BOOL ignore;
    }
    + (instancetype)sharedInstance;
     @end
    
    #import "CrashHandler.h"
    #import <UIKit/UIKit.h>
    #include <libkern/OSAtomic.h>
    #include <execinfo.h>
    
    static CrashHandler *instance = nil;
    NSString * const kSignalExceptionName = @"kSignalExceptionName";
    NSString * const kSignalKey = @"kSignalKey";
    NSString * const kCaughtExceptionStackInfoKey = @"kCaughtExceptionStackInfoKey";
    void HandleException(NSException *exception);
    void SignalHandler(int signal);
    
     @implementation CrashHandler
    
    + (instancetype)sharedInstance {
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
        instance = [[[self class] alloc] init];
      });
      return instance;
    }
    
    + (instancetype)allocWithZone:(struct _NSZone *)zone{
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
        instance = [super allocWithZone:zone];
      });
      return instance;
    }
    
    - (instancetype)init{
      self = [super init];
      if (self) {
        [self setCatchExceptionHandler];
      }
      return self;
    }
    
    - (void)setCatchExceptionHandler{
      // 1.捕获一些异常导致的崩溃
      NSSetUncaughtExceptionHandler(&HandleException);
      // 2.捕获非异常情况,通过signal传递出来的崩溃
      signal(SIGABRT, SignalHandler);
      signal(SIGILL, SignalHandler);
      signal(SIGSEGV, SignalHandler);
      signal(SIGFPE, SignalHandler);
      signal(SIGBUS, SignalHandler);
      signal(SIGPIPE, SignalHandler);
    }
    
    + (NSArray *)backtrace{
      void* callstack[128];
      int frames = backtrace(callstack, 128);
      char **strs = backtrace_symbols(callstack, frames);
       
      NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
      for (int i = 0; i < frames; i++) {
        [backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
      }
      free(strs);
       
      return backtrace;
    }
    - (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex{
      if (anIndex == 0) {
        ignore = YES;
      } else if (anIndex == 1) {
        NSLog(@"起死回生");
      }
    }
    - (void)handleException:(NSException *)exception{
      NSString *message = [NSString stringWithFormat:@"崩溃原因如下:\n%@\n%@",
                 [exception reason],
                 [[exception userInfo] objectForKey:kCaughtExceptionStackInfoKey]];
      NSLog(@"%@",message);
       
      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"程序崩溃了"
                              message:@"如果你能让程序起死回生,那你的决定是?"
                              delegate:self
                         cancelButtonTitle:@"崩就蹦吧"
                         otherButtonTitles:@"起死回生", nil];
      [alert show];
       
      CFRunLoopRef runLoop = CFRunLoopGetCurrent();
      CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
       
      while (!ignore) {
        for (NSString *mode in ( __bridge NSArray *)allModes) {
          CFRunLoopRunInMode((CFStringRef)mode, 0.001, false);
        }
      }
       
      CFRelease(allModes);
       
      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:kSignalExceptionName]) {
        kill(getpid(), [[[exception userInfo] objectForKey:kSignalKey] intValue]);
      } else {
        [exception raise];
      }
    }
     @end
    
    void HandleException(NSException *exception){
      // 获取异常的堆栈信息
      NSArray *callStack = [exception callStackSymbols];
      NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
      [userInfo setObject:callStack forKey:kCaughtExceptionStackInfoKey];
       
      CrashHandler *crashObject = [CrashHandler sharedInstance];
      NSException *customException = [NSException exceptionWithName:[exception name] reason:[exception reason] userInfo:userInfo];
      [crashObject performSelectorOnMainThread: @selector(handleException:) withObject:customException waitUntilDone:YES];
    }
    
    void SignalHandler(int signal){
      // 这种情况的崩溃信息,就另某他法来捕获吧
      NSArray *callStack = [CrashHandler backtrace];
      NSLog(@"信号捕获崩溃,堆栈信息:%@",callStack);
       
      CrashHandler *crashObject = [CrashHandler sharedInstance];
      NSException *customException = [NSException exceptionWithName:kSignalExceptionName
                                  reason:[NSString stringWithFormat:NSLocalizedString(@"Signal %d was raised.", nil),signal]
                                 userInfo:@{kSignalKey:[NSNumber numberWithInt:signal]}];
       
      [crashObject performSelectorOnMainThread: @selector(handleException:) withObject:customException waitUntilDone:YES];
    }
    
    @end
    

    相关文章

      网友评论

          本文标题:iOS 复活崩溃应用及崩溃信息上报

          本文链接:https://www.haomeiwen.com/subject/zxvdkdtx.html