iOS异常处理并发送崩溃报告到服务器:NSSetUncaughtExceptionHandler及signal

在程序中常常会遇到崩溃,我们可以通过以下两种途径来捕获崩溃信息发送到我们的服务器;这两种途径会捕获不同的崩溃信号;

途径一:

void NSSetUncaughtExceptionHandler(NSUncaughtExceptionHandler *);

Discussion
Sets the top-level error-handling function where you can perform last-minute logging before the program terminates.

 

途径二:

 

void    (*signal(int, void (*)(int)))(int);

 

具体代码实现如下:

通过应用程序委托中调用[[AppExceptionHandler shareAppExceptionHandler] start];来开启异常捕获即可;这样,几乎所有的异常信息都能被监听并发送到自己的服务器。
#import <Foundation/Foundation.h>

@interface AppExceptionHandler : NSObject
{
@private
    BOOL _dismissed;
}

+ (AppExceptionHandler*) shareAppExceptionHandler;

- (void)start;

@end
#import "AppExceptionHandler.h"
#include <execinfo.h>
#import <UIKit/UIKit.h>

static NSString * const ExceptionSourceKey = @"ExceptionSource";
static NSString * const CallStackKey = @"CallStack";
static NSString * const SignalValueKey = @"SignalValue";
static NSString * const SignalExceptionName = @"SignalExceptionName";

void InstallExceptionHandler(void);
void UncaughtExceptionHandler(NSException *exception);
void SignalExceptionHandler(int signal);

@implementation AppExceptionHandler

static AppExceptionHandler *shareAppExceptionHandler = nil;

+ (AppExceptionHandler*) shareAppExceptionHandler
{
    @synchronized(self)
    {
        if (shareAppExceptionHandler == nil)
        {
            shareAppExceptionHandler = [[[self class] alloc] init];
        }
    }
    
    return shareAppExceptionHandler;
    
}

- (id) init {
    self = [super init];
    if (self) {
       _dismissed = NO;
    }
    return self;
}

- (void)start
{
//  开始程序异常监听
    InstallExceptionHandler();
}

- (void)handleException:(NSException *)exception
{
//    在这里处理错误报告,例如将错误信息发送到服务器;

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"抱歉,程序出现了异常",nil)
                                                        message:NSLocalizedString(@"建议您点击退出按钮并重新打开。",nil)
                                                       delegate:self
                                              cancelButtonTitle:NSLocalizedString(@"退出",nil)
                                              otherButtonTitles:nil];
    [alertView show];
    
//  等待用户响应按钮
    while (!_dismissed)
    {
        CFRunLoopRunInMode((CFStringRef)UITrackingRunLoopMode, 0.001, false);
        
    }
//  清理异常回调处理函数    
    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:SignalExceptionName])
    {
        kill(getpid(), [exception.userInfo[SignalValueKey] intValue]);
    }
    else
    {
        [exception raise];
  
    }
}

+ (NSArray *)backtrace
{
    void *callstack[128];
    int frames = backtrace(callstack, 128);
    char **strs = backtrace_symbols(callstack, frames);
    
    NSMutableArray *traces = [NSMutableArray arrayWithCapacity:frames];
    for (int i = 0; i < frames; i++)
    {
        [traces addObject:[NSString stringWithUTF8String:strs[i]]];
    }
    free(strs);
    
    return traces;
}

#pragma mark - UIAlertViewDelegate
- (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex
{
    _dismissed = YES;
}

@end

//----------------------------------

void InstallExceptionHandler(void)
{
//  捕获第一种异常,比如内存访问错误,并由UncaughtExceptionHandler回调函数处理
    NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
//  捕获其他异常,比如内存过度释放之类的
    signal(SIGABRT, SignalExceptionHandler);
    signal(SIGILL, SignalExceptionHandler);
    signal(SIGSEGV, SignalExceptionHandler);
    signal(SIGFPE, SignalExceptionHandler);
    signal(SIGBUS, SignalExceptionHandler);
    signal(SIGPIPE, SignalExceptionHandler);
}

void UncaughtExceptionHandler(NSException *exception)
{
//  格式化程序异常时的名称,原因,调用堆栈等信息,这些信息可以返回给服务器
    NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    userInfo[ExceptionSourceKey] = NSLocalizedString(@"UncaughtExceptionHandler",nil);
    userInfo[CallStackKey] = exception.callStackSymbols;
    userInfo[SignalValueKey] = [NSNumber numberWithInt:-99999];
    NSException *newException = [NSException exceptionWithName:exception.name
                                                        reason:exception.reason
                                                      userInfo:userInfo];
    
    [[AppExceptionHandler shareAppExceptionHandler] performSelectorOnMainThread:@selector(handleException:) withObject:newException waitUntilDone:YES];
    
}

void SignalExceptionHandler(int signal)
{
//  格式化程序异常时的名称,原因,调用堆栈等信息,这些信息可以返回给服务器
    NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    userInfo[ExceptionSourceKey] = NSLocalizedString(@"SignalExceptionHandler",nil);
    userInfo[CallStackKey] = [AppExceptionHandler backtrace];
    userInfo[SignalValueKey] = [NSNumber numberWithInt:signal];
    
    NSException *newException = [NSException exceptionWithName:SignalExceptionName
                                                        reason:[NSString stringWithFormat: NSLocalizedString(@"Signal %d was raised.",nil), signal]
                                                      userInfo:userInfo];
    
    [[AppExceptionHandler shareAppExceptionHandler] performSelectorOnMainThread:@selector(handleException:) withObject:newException waitUntilDone:YES];
}

 

具体使用参考DEMO

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值