写在开篇
曾经大牛写的一个框架中用到一个测试导航,可以在整个app最上边点击切换测试环境和正式环境,可以在手机中看到log,map以及crash日志,无论是定位crash,还是定位前后端问题以及服务器环境问题,都十分方便,正在逐步的抽丝剥茧,一层层的分析每个方法都是做什么的。
因为个人能力有限,所以就将看懂的部分整理出来。注释是自己写的,可能有的地方写的不对,还请懂得各位大牛不吝赐教。。。感激不尽。
代码片段
//设置异常捕获句柄
NSSetUncaughtExceptionHandler(&HandleException);
//注册程序由于某件事函数调用发生的程序中止信号
//退出信号
signal(SIGQUIT, SignalHandler);
//非法指令信号
signal(SIGILL, SignalHandler);
//陷阱信号
signal(SIGTRAP, SignalHandler);
//abort()结束函数信号
signal(SIGABRT, SignalHandler);
//???
signal(SIGEMT, SignalHandler);
//浮点数异常
signal(SIGFPE, SignalHandler);
//总线异常
signal(SIGBUS, SignalHandler);
//无效内存
signal(SIGSEGV, SignalHandler);
//系统调用参数错误
signal(SIGSYS, SignalHandler);
//程序socket发送失败
signal(SIGPIPE, SignalHandler);
//程序超时
signal(SIGALRM, SignalHandler);
//CPU超时
signal(SIGXCPU, SignalHandler);
//文件大小超过限制
signal(SIGXFSZ, SignalHandler);```
该段代码主要是设置捕获异常信息
>NSSetUncaughtExceptionHandler
官方的解释为
>sets the top-level error-handling function where you can perform last-minute logging before the program terminates
由于不知道具体实现以及英语水平有限,只能暂时翻译为
>设置当在程序终止前一分钟获取最顶级错误方法
用来捕捉异常,参数为`NSException *exception`这里大牛将这个异常信息在`HandleException`中解析以后做了一下格式化。
其中调取堆栈信息,将堆栈信息打印在log中,方便定位。
随后通过`signal()`来注册需要监控的中止行为。
到此为止,准备工作结束。
`- (BOOL)applictaion:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary * )launchOptions`
在该方法中加入监控上述监控
当app发生crash的时候,系统会自动执行之前预留的方法也就是`HandleException`中
这时候处理传入的异常`(NSException *)exception`
解析其中的你需要的属性`name,reason`等
到此为止,发生的bug就被获取到了,接下来有几个处理方式看公司的需求和个人的习惯。
可以写在本地,在下次打开app的时候打开邮件功能让用户将错误日志发送到指定的邮箱中,但是很多用户可能觉得麻烦不会发。也可以判断当前环境,在wifi的环境下将错误日志上传到服务器,留存。
lastException = exception;
NSMutableString *crash = [NSMutableString stringWithString:writeAppCrashStack(exception)];
// 崩溃信息增加countinue=1,但不写入文件中。可以用该标记来表明程序是否继续运行了。
[crash appendFormat:@"\nCountinue=1"];
// 不允许崩溃次数多余UncaughtExceptionMaximum规定的次数
if (UncaughtExceptionCount>UncaughtExceptionMaximum) {
exitRunning = YES;
}
// 不允许连续两次发生signal错误
static BOOL lastExceptionIsFromSignal = NO;
BOOL isFromSignal = [[exception name] isEqual:UncaughtExceptionHandlerSignalExceptionName];
if (isFromSignal && lastExceptionIsFromSignal) {
exitRunning = YES;
}
lastExceptionIsFromSignal = isFromSignal;
if (exitRunning) {
[self writeToFile:crash];
}
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
BOOL hasRecordException = NO;
while (!exitRunning)
{
for (NSString *mode in (__bridge NSArray *)allModes)
{
CFRunLoopRunInMode((__bridge CFStringRef)mode, 0.001, false);
}
if (!hasRecordException) {
hasRecordException = YES;
[self performSelectorInBackground:@selector(reportAppCrash:) withObject:crash];
}
}
CFRelease(allModes);
// kill app
[self killApp];```
其中writeAppCrashStack
的方法是讲crash日志整理一下,因为这边需要打印环境,需要打印UDID,UUID等,writeToFile
的方法是将crash日志写在本地Document文件夹中。
以上就是初步总结的一些东西,希望有大牛指导,另外可以给再讲一些细节的东西,很多细节的东西还是弄得不是很清楚。
最后附上git上一个关于crash捕捉的代码。
plcrashreportoer
ps.目前还在逐步的看和翻译之中,如果看明白了,再详细解读大牛的思路和讲翻译后的注释呈现给大家。