美文网首页iOS点点滴滴
iOS:app崩溃怎么办?崩溃捕获

iOS:app崩溃怎么办?崩溃捕获

作者: ACMango | 来源:发表于2016-06-28 15:49 被阅读1109次

iOS中App崩溃问题是在所难免的,那如何在崩溃之前给用户一些提示,或是可以将这些崩溃信息发送给自己,以便于自己修正呢?前段时间做项目时,一直没添加这方面的功能,这两天没事从网上看了些资料,顺便自己做了个Demo测试了一下,今天把我了解的东西整理一下。

IOS SDK中提供了一个现成的函数NSSetUncaughtExceptionHandler 用来做异常处理,但功能非常有限,而引起崩溃的大多数原因如:内存访问错误,重复释放等错误就无能为力了,因为这种错误它抛出的是Signal,所以必须要专门做Signal处理。

Demo运行环境:Xcode7.3, iOS9.3

步骤一:定义一个UncaughtExceptionHandler类

UncaughtExceptionHandler.h内容:

#import <UIKit/UIKit.h>

@interface UncaughtExceptionHandler : NSObject
{
  BOOL dismissed;
}

@end

void InstallUncaughtExceptionHandler();

UncaughtExceptionHandler.m内容:

#import "UncaughtExceptionHandler.h"
#include <libkern/OSAtomic.h>
#include <execinfo.h>

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 UncaughtExceptionHandler

+ (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;
}

- (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex
{
    if (anIndex == 0)
    {
        dismissed = YES;
    }
}

- (void)handleException:(NSException *)exception
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"程序出现问题啦", nil) message:[NSString stringWithFormat:NSLocalizedString(@"崩溃信息\n"@"%@\n%@", nil), [exception reason], [[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey]] delegate:self cancelButtonTitle:NSLocalizedString(@"离开", nil) otherButtonTitles:nil];
    [alert show];
    CFRunLoopRef runLoop = CFRunLoopGetCurrent();
    CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
    while (!dismissed)
    {
        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:UncaughtExceptionHandlerSignalExceptionName])
    {
        kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]);
    }
    else
    {
        [exception raise];
    }
}
@end


NSString* getAppInfo()
{
    NSString *appInfo = [NSString stringWithFormat:@"App : %@ %@(%@)\nDevice : %@\nOS Version : %@ %@\n",
                         [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"],
                         [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"],
                         [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"],
                         [UIDevice currentDevice].model,
                         [UIDevice currentDevice].systemName,
                         [UIDevice currentDevice].systemVersion];
    NSLog(@"Crash!!!! %@", appInfo);
    return appInfo;
}

void MySignalHandler(int signal)
{
    int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
    if (exceptionCount > UncaughtExceptionMaximum)
    {
        return;
    }
    NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObject:[NSNumber numberWithInt:signal] forKey:UncaughtExceptionHandlerSignalKey];
    NSArray *callStack = [UncaughtExceptionHandler backtrace];
    [userInfo setObject:callStack forKey:UncaughtExceptionHandlerAddressesKey];
    // 创建一个OC异常对象
    NSException *ex = [NSException exceptionWithName:UncaughtExceptionHandlerSignalExceptionName reason:[NSString stringWithFormat:NSLocalizedString(@"Signal %d was raised.\n"@"%@", nil), signal, getAppInfo()] userInfo:userInfo];
    // 处理异常消息
    [[[UncaughtExceptionHandler alloc] init] performSelectorOnMainThread:@selector(handleException:) withObject:ex waitUntilDone:YES];
}

void InstallUncaughtExceptionHandler()
{
    signal(SIGABRT, MySignalHandler);
    signal(SIGILL, MySignalHandler);
    signal(SIGSEGV, MySignalHandler);
    signal(SIGFPE, MySignalHandler);
    signal(SIGBUS, MySignalHandler);
    signal(SIGPIPE, MySignalHandler);
}
步骤二:在AppDelegate中导入本类
#import "UncaughtExceptionHandler.h"

- (void)installUncaughtExceptionHandler
{
    InstallUncaughtExceptionHandler();
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self installUncaughtExceptionHandler];
    return YES;
}
效果图如下:
崩溃截图.png

当然,也可以把这些崩溃信息通过邮箱发送给自己,这个根据项目需求来自定义。

[参考]http://www.111cn.net/sj/ios8/89772.htm

相关文章

  • iOS:app崩溃怎么办?崩溃捕获

    iOS中App崩溃问题是在所难免的,那如何在崩溃之前给用户一些提示,或是可以将这些崩溃信息发送给自己,以便于自己修...

  • iOS 之 APP 异常崩溃抓取

    iOS 之 APP 异常崩溃抓取 NSSetUncaughtExceptionHandler 自己用程序捕获 cr...

  • iOS app崩溃捕获

    1、信号的理解 信号的概念:信号(本人关于signal的一篇博客) http://www.jianshu.com/...

  • iOS Crash 大解析

    iOS crash / 崩溃/ 异常 /捕获 1 崩溃日志(crash log) Xcode中 查看崩溃信息 手...

  • iOS 捕获崩溃

    用苹果提供的api NSSetUncaughtExceptionHandler进行捕获 void CustomEx...

  • iOS 捕获崩溃

    用苹果提供的api NSSetUncaughtExceptionHandler进行捕获 uncaughtSigna...

  • 精选火热Github项目推荐:xCrash,Android开发的

    xCrash xCrash 能为安卓 APP 提供捕获 java 崩溃,native 崩溃和 ANR 的能力。不需...

  • iOS Crash 流程化0:概览

    Ref:iOS Crash 捕获及堆栈符号化思路剖析 iOS Crash 流程化:概览崩溃捕获Mach 异常捕获U...

  • App Crash崩溃捕获

    参考 https://github.com/android-notes/Cockroach 原理 利用Thread...

  • crash

    来源:iOS崩溃crash大解析 - 简书 1.上线崩溃日志获取 App上线以后苹果就会自动捕捉崩溃信息,当App...

网友评论

    本文标题:iOS:app崩溃怎么办?崩溃捕获

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