1. 在代码中添加手机崩溃日志代码
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
[self updateAppErrorInfo];
return YES;
}
#pragma mark //如果有异常崩溃信息,提交异常
- (void)updateAppErrorInfo
{
NSDictionary * dictionary = [NUD objectForKey:Sandbox_appErrorInfo];
DLog(@"dictionary==%@",dictionary);
//如果有异常崩溃信息,提交异常
if (dictionary&&NotNilAndNull(dictionary[@"content"]))
{
static NSString *AppErrorBaseHostURL = @"http://:8080/appmanage/";//提交到自己的日志平台
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSString * urlString = [[NSString stringWithFormat:@"%@%@",AppErrorBaseHostURL,@"/app/appErrorInfo/add"]stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
NSURL *URL = [NSURL URLWithString:urlString];
manager.requestSerializer.timeoutInterval = 5.f; //请求时间
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager POST:URL.absoluteString parameters:dictionary progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
NSDictionary * dic = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:nil];
DLog(@"dic=========%@",dic);
if ([dic[@"success"] isEqualToString:@"0"]) {
[NUD removeObjectForKey:Sandbox_appErrorInfo];
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
}];
}
}
#pragma mark 收集异常,存储到本地,下次用户打开程序时上传给我们
void UncaughtExceptionHandler(NSException *exception) {
/**
* 获取异常崩溃信息
*/
NSArray *callStack = [exception callStackSymbols];
NSString *reason = [exception reason];
NSString *name = [exception name];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
NSString * dateStr = [formatter stringFromDate:[NSDate date]];
NSString * userID = [NUD objectForKey:USERID];
NSString * userName = [NUD objectForKey:USERNAME];
NSString * iOS_Version = [[UIDevice currentDevice] systemVersion];
NSString * PhoneSize = NSStringFromCGSize([[UIScreen mainScreen] bounds].size);
NSString * App_Version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
NSString * iPhoneType = [RSToolNSObject getiPhoneType];
NSString *content = [NSString stringWithFormat:@"%@<br>\niOS_Version : %@----PhoneSize : %@<br>\n----iPhoneType: %@<br>\nApp_Version : %@<br>\nuserID : %@<br>\nuserName : %@<br>\nname:%@<br>\nreason:\n%@<br>\ncallStackSymbols:\n%@",dateStr,iOS_Version,PhoneSize,iPhoneType,App_Version,userID,userName,name,reason,[callStack componentsJoinedByString:@"\n"]];
#if DEBUG
NSDictionary * dictionary = @{@"content":content,
@"isDebug":@(1),
@"packageName":@"com.thinkjoy.NetworkTaxiDriver"};
#else
NSDictionary * dictionary = @{@"content":content,
@"isDebug":@(0),
@"packageName":@"com.thinkjoy.NetworkTaxiDriver"};
#endif
[NUD setObject:dictionary forKey:Sandbox_appErrorInfo];
}
#pragma mark 获得设备型号
+ (NSString *)getiPhoneType
{
struct utsname systemInfo;
uname(&systemInfo);
NSString *platform = [NSString stringWithCString:systemInfo.machine encoding:NSASCIIStringEncoding];
if ([platform isEqualToString:@"iPhone1,1"]) return @"iPhone 2G";
if ([platform isEqualToString:@"iPhone1,2"]) return @"iPhone 3G";
if ([platform isEqualToString:@"iPhone2,1"]) return @"iPhone 3GS";
if ([platform isEqualToString:@"iPhone3,1"]) return @"iPhone 4";
if ([platform isEqualToString:@"iPhone3,2"]) return @"iPhone 4";
if ([platform isEqualToString:@"iPhone3,3"]) return @"iPhone 4";
if ([platform isEqualToString:@"iPhone4,1"]) return @"iPhone 4S";
if ([platform isEqualToString:@"iPhone5,1"]) return @"iPhone 5";
if ([platform isEqualToString:@"iPhone5,2"]) return @"iPhone 5";
if ([platform isEqualToString:@"iPhone5,3"]) return @"iPhone 5c";
if ([platform isEqualToString:@"iPhone5,4"]) return @"iPhone 5c";
if ([platform isEqualToString:@"iPhone6,1"]) return @"iPhone 5s";
if ([platform isEqualToString:@"iPhone6,2"]) return @"iPhone 5s";
if ([platform isEqualToString:@"iPhone7,1"]) return @"iPhone 6 Plus";
if ([platform isEqualToString:@"iPhone7,2"]) return @"iPhone 6";
if ([platform isEqualToString:@"iPhone8,1"]) return @"iPhone 6s";
if ([platform isEqualToString:@"iPhone8,2"]) return @"iPhone 6s Plus";
if ([platform isEqualToString:@"iPhone8,4"]) return @"iPhone SE";
if ([platform isEqualToString:@"iPhone9,1"]) return @"iPhone 7";
if ([platform isEqualToString:@"iPhone9,2"]) return @"iPhone 7 Plus";
if ([platform isEqualToString:@"iPod1,1"]) return @"iPod Touch 1G";
if ([platform isEqualToString:@"iPod2,1"]) return @"iPod Touch 2G";
if ([platform isEqualToString:@"iPod3,1"]) return @"iPod Touch 3G";
if ([platform isEqualToString:@"iPod4,1"]) return @"iPod Touch 4G";
if ([platform isEqualToString:@"iPod5,1"]) return @"iPod Touch 5G";
if ([platform isEqualToString:@"iPad1,1"]) return @"iPad 1G";
if ([platform isEqualToString:@"iPad2,1"]) return @"iPad 2";
if ([platform isEqualToString:@"iPad2,2"]) return @"iPad 2";
if ([platform isEqualToString:@"iPad2,3"]) return @"iPad 2";
if ([platform isEqualToString:@"iPad2,4"]) return @"iPad 2";
if ([platform isEqualToString:@"iPad2,5"]) return @"iPad Mini 1G";
if ([platform isEqualToString:@"iPad2,6"]) return @"iPad Mini 1G";
if ([platform isEqualToString:@"iPad2,7"]) return @"iPad Mini 1G";
if ([platform isEqualToString:@"iPad3,1"]) return @"iPad 3";
if ([platform isEqualToString:@"iPad3,2"]) return @"iPad 3";
if ([platform isEqualToString:@"iPad3,3"]) return @"iPad 3";
if ([platform isEqualToString:@"iPad3,4"]) return @"iPad 4";
if ([platform isEqualToString:@"iPad3,5"]) return @"iPad 4";
if ([platform isEqualToString:@"iPad3,6"]) return @"iPad 4";
if ([platform isEqualToString:@"iPad4,1"]) return @"iPad Air";
if ([platform isEqualToString:@"iPad4,2"]) return @"iPad Air";
if ([platform isEqualToString:@"iPad4,3"]) return @"iPad Air";
if ([platform isEqualToString:@"iPad4,4"]) return @"iPad Mini 2G";
if ([platform isEqualToString:@"iPad4,5"]) return @"iPad Mini 2G";
if ([platform isEqualToString:@"iPad4,6"]) return @"iPad Mini 2G";
if ([platform isEqualToString:@"i386"]) return @"iPhone Simulator";
if ([platform isEqualToString:@"x86_64"]) return @"iPhone Simulator";
return platform;
}
2. 收集到的崩溃日志如下
name:NSInvalidArgumentException<br>
reason:
*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[0]<br>
callStackSymbols:
0 CoreFoundation 0x2141a303 <redacted> + 150
1 libobjc.A.dylib 0x20be6dff objc_exception_throw + 38
2 CoreFoundation 0x21337e2b <redacted> + 342
3 CoreFoundation 0x21337caf <redacted> + 50
4 NetworkTaxiDriver 0x0012ff29 NetworkTaxiDriver + 323369
5 NetworkTaxiDriver 0x0013019f NetworkTaxiDriver + 323999
6 UIKit 0x25695d29 <redacted> + 2976
7 UIKit 0x2569507b <redacted> + 378
8 UIKit 0x2569c995 <redacted> + 328
9 UIKit 0x25735f45 <redacted> + 488
10 NetworkTaxiDriver 0x0013013b NetworkTaxiDriver + 323899
11 UIKit 0x255b1d79 <redacted> + 1028
12 UIKit 0x255b1959 <redacted> + 24
13 UIKit 0x2566f4d5 <redacted> + 280
14 UIKit 0x2566e8e5 <redacted> + 96
15 UIKit 0x2566e51b <redacted> + 834
16 UIKit 0x2566e16d <redacted> + 52
17 UIKit 0x2566e0e7 <redacted> + 214
18 UIKit 0x255ada83 <redacted> + 714
19 QuartzCore 0x23689ad5 <redacted> + 128
20 QuartzCore 0x236851d1 <redacted> + 352
21 QuartzCore 0x23685061 <redacted> + 16
22 QuartzCore 0x23684581 <redacted> + 368
23 QuartzCore 0x23684233 <redacted> + 614
24 UIKit 0x255b08d7 <redacted> + 5518
25 CoreFoundation 0x213dd257 <redacted> + 14
26 CoreFoundation 0x213dce47 <redacted> + 454
27 CoreFoundation 0x213db1af <redacted> + 806
28 CoreFoundation 0x2132dbb9 CFRunLoopRunSpecific + 516
29 CoreFoundation 0x2132d9ad CFRunLoopRunInMode + 108
30 GraphicsServices 0x225a7af9 GSEventRunModal + 160
31 UIKit 0x25619fb5 UIApplicationMain + 144
32 NetworkTaxiDriver 0x0013f46d NetworkTaxiDriver + 386157
33 libdyld.dylib 0x20fe0873 <redacted> + 2
dSYM符号表获取
xcode->window->organizer->右键你的应用 show finder->右键.xcarchive 显示包内容->dSYMs->test.app.dYSM
atos命令
atos命令来符号化某个特定模块加载地址
atos [-arch 架构名] [-o 符号表] [-l 模块地址] [方法地址]
使用终端计算
1.没有模块地址,需要自己计算。
4 NetworkTaxiDriver 0x00116f29 NetworkTaxiDriver + 323369
0x00116f29 = 1142569; //将方法地主转化为十进制
1142569-323369 = 819200;//减去偏移地址,得到模块地址
819200 = 0xc8000; //得到的模块地址在转为十六进制
终端示例:
//打开文件
cd /Users/thinkjoy/Desktop/出租车/出租车V1.6崩溃分析/NetworkTaxiDriver.app.dSYM
//根据模块地址和方法地址计算问题代码位置
atos -arch armv7 -o /Users/thinkjoy/Desktop/出租车/出租车V1.6崩溃分析/NetworkTaxiDriver.app.dSYM/Contents/Resources/DWARF/NetworkTaxiDriver -l 0xc8000 0x00116f29
//问题代码的位置
-[RSUserMessageVC messageListAry] (in NetworkTaxiDriver) (RSUserMessageVC.m:54)
thinkjoytekiMacBook-Pro:NetworkTaxiDriver.app.dSYM thinkjoy$
注意:使用armv7
和arm64
定位到的代码完全不同。
2.有模块地址,可以直接计算。
test 0x00000001018157dc 0x100064000 + 24844252
0x00000001018157dc
代码地址,0x100064000
模块地址;