ios Crash闪退日志获取和上传至服务器(NSSetUncaughtExceptionHandler)

286 篇文章 2 订阅

最近客户有个要求:人家谁谁有crash日志捕获和上传,我们是不是也要做一个... 人家谁谁.....还有什么什么功能........

正好最近也在研究这方面东东,所以整理一下分享给大家:如何用程序获取Crash日志 并 可以上传Crash日志。

首先我们整理经常会闪退的异常哪些:数组越界、空引用、引用未定义方法、内存空间不足等等。

友盟分享后台是可以看到crash的日志,如下图:

开始研究的时候,我有两个疑问:

1.如何获取crash闪退日志(工具和程序两种方法);

2.解析crash;

说明:这里说的crash日志不是在联调的情况下(是生产环境,通俗的说就是发布了的产品)。

如何获取crash闪退日志-- 工具查看

先看第一个问题如何查看,我搜索的方法有以下几个:

第一个方法:XCode 的菜单Window->Organizer 选择Devices -> 选中的手机 -> 点击手机名称左边的箭头 会等到如下图

在右边竖蓝色矩形框中 Type里面出现两种类型:Unknown和Crash 这两种类型分别是 内存不够回收内存kill应用程序导致Crash和程序异常Crash的日志。

上图是我在刚打开日志(立马、马上)截的图,否则过了5秒中,会变成这样(自动解析):

注意对比一下红色框框内容,这个日志也基本上上告诉你crash的原因了。

第二种方法 打开手机 - > 设置 -> 通用 - > 关于本机 - > 诊断与用量 - > 诊断与用量数据 这里面就是所有应用的Crash日志。

第三种方法 通过iTunes Connect(Manage Your Applications - View Details - Crash Reports)获取用户的crash日志。方法很多这里不多列了。

解析crash

参见:http://stackoverflow.com/questions/1460892/symbolicating-iphone-app-crash-reports )

用程序获取crash日志

但是这里都是工具,没有用到程序获取,经过千方百计的查询(思路是:先找到存放crash的iphone系统路径:var/mobile/Library/Logs/CrashReporter)找到了crash存放的路径,唉,苦于无法读取(用程序读出来都是nil),当然如果是越狱手机就不一样是可以读取的。这个思路断掉了。

换个思路:自己用程序捕获crash,保存到本地可以吗?这么一试,果然........

第一步:新建一个继承自NSObject的类(Xcode新建一个空项目过程略),取名字CatchCrash,在h和m文件中写下:

.h文件

  1. #import<Foundation/Foundation.h>
  2.  
  3. @interfaceCatchCrash:NSObject
  4.  
  5. voiduncaughtExceptionHandler(NSException*exception);
  6.  
  7. @end

.m(m)文件

  1. #import"CatchCrash.h"
  2.  
  3. @implementationCatchCrash
  4.  
  5. voiduncaughtExceptionHandler(NSException*exception)
  6. {
  7. //异常的堆栈信息
  8. NSArray*stackArray=[exceptioncallStackSymbols];
  9. //出现异常的原因
  10. NSString*reason=[exceptionreason];
  11. //异常名称
  12. NSString*name=[exceptionname];
  13. NSString*exceptionInfo=[NSStringstringWithFormat:@"Exceptionreason:%@nExceptionname:%@nExceptionstack:%@",name,reason,stackArray];
  14. NSLog(@"%@",exceptionInfo);
  15.  
  16. NSMutableArray*tmpArr=[NSMutableArrayarrayWithArray:stackArray];
  17. [tmpArrinsertObject:reasonatIndex:0];
  18.  
  19. //保存到本地--当然你可以在下次启动的时候,上传这个log
  20. [exceptionInfowriteToFile:[NSStringstringWithFormat:@"%@/Documents/error.log",NSHomeDirectory()]atomically:YESencoding:NSUTF8StringEncodingerror:nil];
  21. }
  22.  
  23. @end

第二步:添加一个继承自UIViewcontroller的类,取名字为TestViewController。

第三步:注册CatchCrash异常处理方法,在Appdelegate写下如下代码:

  1. #import"AppDelegate.h"
  2. #import"CatchCrash.h"
  3. #import"TestViewController.h"
  4.  
  5. @implementationAppDelegate
  6.  
  7. -(BOOL)application:(UIApplication*)applicationdidFinishLaunchingWithOptions:(NSDictionary*)launchOptions
  8. {
  9. self.window=[[UIWindowalloc]initWithFrame:[[UIScreenmainScreen]bounds]];
  10. //Overridepointforcustomizationafterapplicationlaunch.
  11.  
  12. //注册消息处理函数的处理方法
  13. NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
  14.  
  15. TestViewController*testVc=[[TestViewControlleralloc]init];
  16. self.window.rootViewController=testVc;
  17.  
  18. self.window.backgroundColor=[UIColorwhiteColor];
  19. [self.windowmakeKeyAndVisible];
  20. returnYES;
  21. }
  22.  
  23. -(void)applicationWillResignActive:(UIApplication*)application
  24. {}
  25.  
  26. -(void)applicationDidEnterBackground:(UIApplication*)application
  27. {}
  28.  
  29. -(void)applicationWillEnterForeground:(UIApplication*)application
  30. {}
  31.  
  32. -(void)applicationDidBecomeActive:(UIApplication*)application
  33. {}
  34.  
  35. -(void)applicationWillTerminate:(UIApplication*)application
  36. {}

第四部:在TestViewController的Xib上面添加一个按钮并给其添加一个单击事件,TestViewController.m文件中有如下代码:

  1. #import"TestViewController.h"
  2.  
  3. @interfaceTestViewController()
  4.  
  5. @end
  6.  
  7. @implementationTestViewController
  8.  
  9. -(id)initWithNibName:(NSString*)nibNameOrNilbundle:(NSBundle*)nibBundleOrNil
  10. {
  11. self=[superinitWithNibName:nibNameOrNilbundle:nibBundleOrNil];
  12. if(self){
  13. //Custominitialization
  14. }
  15. returnself;
  16. }
  17.  
  18. -(void)viewDidLoad
  19. {
  20. [superviewDidLoad];
  21. //Doanyadditionalsetupafterloadingtheviewfromitsnib.
  22. }
  23.  
  24. -(void)didReceiveMemoryWarning
  25. {
  26. [superdidReceiveMemoryWarning];
  27. //Disposeofanyresourcesthatcanberecreated.
  28. }
  29.  
  30. #pragmamark-单击事件
  31. -(IBAction)crashTapped:(id)sender
  32. {
  33. //常见异常1---不存在方法引用
  34. //[selfperformSelector:@selector(thisMthodDoesNotExist)withObject:nil];
  35.  
  36. //常见异常2---键值对引用nil
  37. //[[NSMutableDictionarydictionary]setObject:nilforKey:@"nil"];
  38.  
  39. //常见异常3---数组越界
  40. [[NSArrayarray]objectAtIndex:1];
  41.  
  42. //常见异常4---memorywarning级别3以上
  43. //[selfperformSelector:@selector(killMemory)withObject:nil];
  44.  
  45. //其他大家去想吧
  46. }
  47.  
  48. #pragmamark-custommethod
  49. -(void)killMemory
  50. {
  51. for(inti=0;i<300;i++)
  52. {
  53. UILabel*tmpLabel=[[UILabelalloc]initWithFrame:CGRectMake(0,0,320,200)];
  54. tmpLabel.layer.masksToBounds=YES;
  55. tmpLabel.layer.cornerRadius=10;
  56. tmpLabel.backgroundColor=[UIColorredColor];
  57. [self.viewaddSubview:tmpLabel];
  58. }
  59. }
  60.  
  61. @end

运行代码:可以看到闪退,我们用iExplorer打开:

导出error日志,我们可以看到:

  1. Exceptionreason:NSRangeException
  2. <spanstyle="color:#FF0000;">Exceptionname:***-[__NSArrayIobjectAtIndex:]:index1beyondboundsforemptyarray</span>
  3. Exceptionstack:(
  4. 0CoreFoundation0x2f2edfeb<redacted>+154
  5. 1libobjc.A.dylib0x39b66ccfobjc_exception_throw+38
  6. 2CoreFoundation0x2f224a89<redacted>+176
  7. <spanstyle="color:#FF0000;">3TestCrash0x000e8077-[TestViewControllercrashTapped:]+126</span>
  8. 4UIKit0x31b3f057<redacted>+90
  9. 5UIKit0x31b3eff7<redacted>+30
  10. 6UIKit0x31b3efd1<redacted>+44
  11. 7UIKit0x31b2a737<redacted>+374
  12. 8UIKit0x31b3ea4f<redacted>+590
  13. 9UIKit0x31b3e721<redacted>+528
  14. 10UIKit0x31b396eb<redacted>+758
  15. 11UIKit0x31b0e8ed<redacted>+196
  16. 12UIKit0x31b0cf97<redacted>+7102
  17. 13CoreFoundation0x2f2b925b<redacted>+14
  18. 14CoreFoundation0x2f2b872b<redacted>+206
  19. 15CoreFoundation0x2f2b6f1f<redacted>+622
  20. 16CoreFoundation0x2f221f0fCFRunLoopRunSpecific+522
  21. 17CoreFoundation0x2f221cf3CFRunLoopRunInMode+106
  22. 18GraphicsServices0x3417a663GSEventRunModal+138
  23. 19UIKit0x31b6d16dUIApplicationMain+1136
  24. 20TestCrash0x000e810dmain+116
  25. 21libdyld.dylib0x3a073ab7<redacted>+2
  26. )

太清楚了,对吧,下次启动应用程序的时候可以把这个error.log(这个名字我临时写的,用什么日期也可以的)上传。可以在日志中加上类似与友盟的 iphone 的UUID、Bundle ID 等等。

现在猜测一下,友盟是不是这么做的呢?

进入一个引用友盟sdk项目的根目录,打开mac终端输入命令grep -r NSSetUncaughtExceptionHandler .(这个点不能少或者绝对路径替换这个点),得到如下图:

真的就找到了,什么什么 matches。当然这只是猜测。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值