iOS中崩溃收集

对于崩溃的收集有很多第三方的不错的工具,比如Bugly。但是如果想要自己收集崩溃日志(比如对于企业内部发布的应用,在局域网内使用),自然也是有方法的。

这里介绍两种抓取崩溃堆栈信息的方法,如果发现问题,希望不吝赐教。也算是给自己做个笔记。:-)

方法一:自己调用c函数抓取堆栈信息,话不多说,代码来

#import <Foundation/Foundation.h>

extern NSString *const SKSAppExceptionInfo;

@interface SKSExceptionRecord : NSObject

+ (void)startExceptionHandler;

@end

#import "SKSExceptionRecord.h"

#include <execinfo.h>

NSString *const SKSAppExceptionInfo = @"SKSAppExceptionInfo";

static int s_fatal_signals[] = {

SIGABRT,

SIGBUS,

SIGFPE,

SIGILL,

SIGSEGV,

SIGTRAP,

SIGTERM,

SIGKILL,

};

static const char* s_fatal_signal_names[] = {

"SIGABRT",

"SIGBUS",

"SIGFPE",

"SIGILL",

"SIGSEGV",

"SIGTRAP",

"SIGTERM",

"SIGKILL",

};

static int s_fatal_signal_num = sizeof(s_fatal_signals) / sizeof(s_fatal_signals[0]);

//信号处理函数

void signalHandler(int signal) {

for (int i = 0; i < s_fatal_signal_num; ++i) {

if (signal == s_fatal_signals[i]) {

//signal 异常不上传log,但还需捕捉,不然Exception异常也不上传

//[SKSExceptionRecord handleException:[NSString stringWithFormat:@"%s",s_fatal_signal_names[i]] description:[SKSExceptionRecord backtrace]];

break;

}

}

}

void exceptionHandler(NSException *exception) {

[SKSExceptionRecord handleException:[exception reason] description:[exception callStackSymbols]];

}

@implementation SKSExceptionRecord

+ (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)startCrashHandler

{

// 1     linux错误信号捕获

for (int i = 0; i < s_fatal_signal_num; ++i) {

signal(s_fatal_signals[i], signalHandler);

}

// 2      objective-c未捕获异常的捕获

NSSetUncaughtExceptionHandler(&exceptionHandler);

}

+ (void)handleException:(NSString *)reason description:(id)description

{

//这里抛出消息,应用中可根据需要监听该消息,做相应的崩溃处理,比如上传到服务器

NSDictionary *dicInfo = [NSDictionary dictionaryWithObjectsAndKeys:reason, @"reason", description, @"description", nil];

[[NSNotificationCenter defaultCenter] postNotificationName:SKSAppExceptionInfo object:nil userInfo:dicInfo];

//[self keepAppSurvive];

}

//+ (void)keepAppSurvive

//{

//    CFRunLoopRef runLoop = CFRunLoopGetCurrent();

//    CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);

//

//    //BOOL dismissed = NO;

//    while (YES)

//    {

//        for (NSString *mode in (__bridge NSArray *)allModes)

//        {

//            CFRunLoopRunInMode((__bridge CFStringRef)mode, 0.001, false);

//        }

//        sleep(2);

//        //dismissed = YES;

//    }

//

//    CFRelease(allModes);

//}

@end

此方法的缺陷,如果符号表被disable,那么抓取的信息将不具有可读性,只是纯粹的内存堆栈。

方法二:使用KSCrash,它的好处是可以将崩溃堆栈直接解析成可读字符。首先需要去git下载KSCrash,将其中的source目录添加到应用工程,或是将KSCrash工程直接添加到应用。添加后基本需要扩展自己的方法来处理崩溃信息,因为其中已经包含的方法(比如邮件)可能并不是你想要的长久的崩溃追踪方法。

以下是我定义的崩溃log收集方法:

#import <Foundation/Foundation.h>

#import "KSCrashInstallation.h"

#import "KSCrash.h"

#import "KSCrashAdvanced.h"

@interface SKSCrashManager : NSObject

+ (SKSCrashManager *)sharedManager;

- (void)checkLocalCrashLogs:(KSCrashReportFilterCompletion)block;

@end

#import "SKSCrashManager.h"

#import "KSCrashInstallation+Private.h"

#import "KSSingleton.h"

#import "KSCrashReportFilterAppleFmt.h"

#import "SkySeaManager.h"

#import "SKSEncrypt.h"

NSString *const SKSAppExceptionWithKSCrash = @"SKSAppExceptionWithKSCrash";

//-----------------SKSCrashReportSink----------------------------------------------

@interface SKSCrashReportSink : NSObject <KSCrashReportFilter>

- (id <KSCrashReportFilter>) defaultCrashReportFilterSet;

@end

@implementation SKSCrashReportSink

- (id <KSCrashReportFilter>) defaultCrashReportFilterSet

{

//这个方法很重要,KSAppleReportStyleSymbolicated这种格式的才能返回可读的crash log

return [KSCrashReportFilterPipeline filterWithFilters:

[KSCrashReportFilterAppleFmt filterWithReportStyle:KSAppleReportStyleSymbolicated],

self,

nil];

}

- (void) filterReports:(NSArray*) reports

onCompletion:(KSCrashReportFilterCompletion) onCompletion

{

NSDictionary *dicInfo = [NSDictionary dictionaryWithObjectsAndKeys:reports, @"reports", onCompletion, @"callback", nil];

[[NSNotificationCenter defaultCenter] postNotificationName:SKSAppExceptionWithKSCrash object:nil userInfo:dicInfo];

}

@end

//--------------------SKSCrashInstallation-----------------------------------------

@interface SKSCrashInstallation : KSCrashInstallation

+ (SKSCrashInstallation*) sharedInstance;

@end

@implementation SKSCrashInstallation

IMPLEMENT_EXCLUSIVE_SHARED_INSTANCE(SKSCrashInstallation)

- (id) init

{

if((self = [super initWithRequiredProperties:nil]))

{

}

return self;

}

- (id<KSCrashReportFilter>) sink

{

SKSCrashReportSink* sink = [[SKSCrashReportSink alloc] init];

return [KSCrashReportFilterPipeline filterWithFilters:[sink defaultCrashReportFilterSet], nil];

}

@end

static SKSCrashManager *g_crashManager = NULL;

@interface SKSCrashManager()

@property (strong, nonatomic) KSCrashInstallation* crashInstallation;

@end

@implementation SKSCrashManager

+ (SKSCrashManager *)sharedManager {

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

if (g_crashManager == NULL) {

g_crashManager = [[SKSCrashManager alloc] init];

[g_crashManager installCrashHandler];

}

});

return g_crashManager;

}

- (void)dealloc

{

[[NSNotificationCenter defaultCenter] removeObserver:self];

}

- (void) installCrashHandler

{

[self configureAdvancedSettings];

self.crashInstallation = [SKSCrashInstallation sharedInstance];

[self.crashInstallation install];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(uploadExceptionLog:) name:SKSAppExceptionWithKSCrash object:nil];

}

static void advanced_crash_callback(const KSCrashReportWriter* writer)

{

// You can add extra user data at crash time if you want.

writer->addBooleanElement(writer, "some_bool_value", NO);

}

- (void) configureAdvancedSettings

{

KSCrash* handler = [KSCrash sharedInstance];

handler.deleteBehaviorAfterSendAll = KSCDeleteOnSucess;

handler.zombieCacheSize = 16384*4;

handler.deadlockWatchdogInterval = 0;

handler.userInfo = @{@"someKey": @"someValue"};

handler.onCrash = advanced_crash_callback;

handler.printTraceToStdout = NO;

handler.searchThreadNames = YES;

handler.searchQueueNames = YES;

handler.handlingCrashTypes = KSCrashTypeAll;

}

- (void)checkLocalCrashLogs:(KSCrashReportFilterCompletion)block {

[self.crashInstallation sendAllReportsWithCompletion:block];

}

- (void)uploadExceptionLog:(NSNotification *)note

{

//这里做相应的崩溃处理

}

@end

以上都是在抓取到崩溃后,抛出消息,然后可以在任意地方做崩溃处理。可以依据自己架构需求做相应地改动。

时间: 2024-08-01 20:59:26

iOS中崩溃收集的相关文章

iOS中崩溃调试的使用和技巧总结 韩俊强的博客

每日更新关注:http://weibo.com/hanjunqiang  新浪微博 在iOS开发调试过程中以及上线之后.程序经常会出现崩溃的问题.简单的崩溃还好说,复杂的崩溃就须要我们通过解析Crash文件来分析了,解析Crash文件在iOS开发中是比較常见的. 如今网上有非常多关于解析崩溃信息的博客.可是大多质量參差不齐,或者有些细节没有注意到.今天写一篇博客总结一下我对崩溃调试的使用和技巧,假设有哪些错误或遗漏.还请指点.谢谢. 获取崩溃信息 在iOS中获取崩溃信息的方式有非常多,比較常见的

React Native的iOS开发步骤以及崩溃收集

React Native的iOS开发以及崩溃收集 简介 React Native使你能够在Javascript和React的基础上获得完全一致的开发体验,构建世界一流的原生APP. React Native着力于提高多平台开发的开发效率 -- 仅需学习一次,编写任何平台.(Learn once, write anywhere) Facebook已经在多项产品中使用了React Native,并且将持续地投入建设React Native. 准备 安装 iOS只能MAC下开发,需要Xcode; An

iOS 中捕获程序崩溃日志

iOS开发中遇到程序崩溃是很正常的事情,如何在程序崩溃时捕获到异常信息并通知开发者,是大多数软件都选择的方法.下面就介绍如何在iOS中实现: 1. 在程序启动时加上一个异常捕获监听,用来处理程序崩溃时的回调动作  NSSetUncaughtExceptionHandler (&UncaughtExceptionHandler);  官方文档介绍:Sets the top-level error-handling function where you can perform last-minute

ios中的奇怪崩溃Signal和EXC_BAD_ACCESS错误分析

什么是Signal 在计算机科学中,信号(英语:Signals)是Unix.类Unix以及其他POSIX兼容的操作系统中进程间通讯的一种有限制的方式.它是一种异步的通知机制,用来提醒进程一个事件已经发生.当一个信号发送给一个进程,操作系统中断了进程正常的控制流程,此时,任何非原子操作都将被中断.如果进程定义了信号的处理函数,那么它将被执行,否则就执行默认的处理函数. 在iOS中就是未被捕获的Objective-C异常(NSException),导致程序向自身发送了SIGABRT信号而崩溃. Si

善用iOS中webview(转)

iOS开发中webview和native code写这是一件纠结的事?我写这篇文章, 介绍一下我做iOS两年来总结的一些在webview和native code的配合上的一些经验和技巧,当然,都是基于互联网App的,希望对大家有所帮助. 首先提两句两者的优劣?webview与运维成本低, 更新几乎不依赖App的版本:但在交互和性能上与跟native code有很大差距.native code与之对应. 注,我这里不说HTML5,因为我认为,HTML5确实给web带入了一个新时代.这个时代是什么,

iOS学习资源收集

https://github.com/Tim9Liu9/TimLiu-iOS 自己总结的iOS.mac开源项目及库,持续更新.... github排名 https://github.com/trending,github搜索:https://github.com/search 目录 UI 下拉刷新 模糊效果 AutoLayout 富文本 图表 表相关与Tabbar 隐藏与显示 HUD与Toast 对话框 其他UI 动画 侧滑与右滑返回手势 gif动画 其他动画 网络相关 网络连接 图像获取 网络

iOS中的通知(NSNotification)

iOS中的通知(NSNotification) 前言 通知中心是一个单例.通知在iOS中是一种设计模式.每一个应用程序都有一个通知中心NSNotificationCenter实例, 专门负责协助不同对象之间的消息通信. 任何一个对象都可以向通知中心发布NSNotification, 描述自己在做什么,而任何注册了该通知的对象该特定通知发布的时候会收到这个通知. 获取通知中心对象 通过下面的方式来获取通知中心对象: 1 2 3 NSNotificationCenter *center = [NSN

[转] ios中KeyChain用途

转自  http://www.2cto.com/kf/201311/255684.html 一.在应用间利用KeyChain共享数据 我们可以把KeyChain理解为一个Dictionary,所有数据都以key-value的形式存储,可以对这个Dictionary进行add. update.get.delete这四个操作.对于每一个应用来说,KeyChain都有两个访问区,私有区和公共区.私有区是一个sandbox,本 程序存储的任何数据都对其他程序不可见.而要想在将存储的内容放在公共区,需要先

ios中KeyChain用途

一.在应用间利用KeyChain共享数据 我们可以把KeyChain理解为一个Dictionary,所有数据都以key-value的形式存储,可以对这个Dictionary进行add.update.get.delete这四个操作.对于每一个应用来说,KeyChain都有两个访问区,私有区和公共区.私有区是一个sandbox,本程序存储的任何数据都对其他程序不可见.而要想在将存储的内容放在公共区,需要先声明公共区的名称,官方文档管这个名称叫“keychain access group”,声明的方法