在我们开发的应用中,总是不可避免地会产生Bug。要是能够把应用的崩溃信息收集起来并传到我们能够接收到的地方,那么对于已发布上线的应用所发生的崩溃我们就能够很好地对其进行分析了。
这里要提到的一个函数就是在iOS SDK中自带的NSSetUncaughtExceptionHandler,可用来做异常处理,但功能较为有限,而引起崩溃的大多数原因如:内存访问错误,重复释放等错误就无能为力了,因为这种错误它抛出的是Signal,所以必须要专门做Signal处理。
下面分享我的做法:
在AppDelegate.m文件中的didFinishLaunchingWithOptions方法中,
[self creatExceptionText];
//注册异常崩溃消息处理函数的处理方法
NSSetUncaughtExceptionHandler (&UncaughtExceptionHandler);
void UncaughtExceptionHandler(NSException *exception) {
NSMutableDictionary *logDic = [[NSMutableDictionary alloc]init];
[logDic setObject:[NSDate date] forKey:@"date"];
// exception info 崩溃/异常信息
NSArray *arr = [exception callStackSymbols];
NSString *reason = [exception reason];
NSString *name = [exception name];
[logDic setObject:name forKey:@"name"];
[logDic setObject:reason forKey:@"reason"];
[logDic setObject:[arr componentsJoinedByString:@"\n"] forKey:@"log"];
// Device info 设备信息
[logDic setObject:[UIDevice currentDevice].model forKey:@"device"];
[logDic setObject:[UIDevice currentDevice].systemVersion forKey:@"osversion"];
// batteryLevel info 电池剩余电量信息
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
[logDic setObject:[NSNumber numberWithFloat:[UIDevice currentDevice].batteryLevel*100] forKey:@"batteryLevel"];
[[UIDevice currentDevice] setBatteryMonitoringEnabled:NO];
NSString *path = logPathUrl();
NSDictionary *logfile = [NSDictionary dictionaryWithDictionary:logDic];
[logfile writeToFile:path atomically:YES];//把错误日志写入文件
}
/**
获取崩溃日志的文件路径
@return 崩溃日志的文件路径
*/
NSString *logPathUrl() {
return [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"Carsh.txt"];
}
- (void)creatExceptionText{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *document = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docu = [document firstObject];
NSString *filePath = [docu stringByAppendingPathComponent:@"Carsh.txt"];
if (![fileManager fileExistsAtPath:filePath]) {
[fileManager createFileAtPath:filePath contents:nil attributes:nil];
}
else{
//1、日志是否有内容
NSData *data = [NSData dataWithContentsOfFile:filePath];
if (data.length > 0) {
//2、则把崩溃日志文件上传至服务器中
if ([Utils httpPostCrashFile:filePath]) {
//3、最后是否成功移除崩溃日志
if([fileManager removeItemAtPath:filePath error:nil]){
NSLog(@"Carsh.txt remove successful");
}
}
}
}
}