最近客戶有個要求:人家誰誰有crash日誌捕獲和上傳,咱們是否是也要作一個... 人家誰誰.....還有什麼什麼功能........數組
正好最近也在研究這方面東東,因此整理一下分享給你們:如何用程序獲取Crash日誌 並 能夠上傳Crash日誌。app
首先咱們整理常常會閃退的異常哪些:數組越界、空引用、引用未定義方法、內存空間不足等等。iphone
友盟分享後臺是能夠看到crash的日誌,以下圖:ide
開始研究的時候,我有兩個疑問:函數
1.如何獲取crash閃退日誌(工具和程序兩種方法);工具
2.解析crash;oop
說明:這裏說的crash日誌不是在聯調的狀況下(是生產環境,通俗的說就是發佈了的產品)。this
如何獲取crash閃退日誌 -- 工具查看
atom
先看第一個問題如何查看,我搜索的方法有如下幾個:spa
第一個方法:XCode 的菜單Window->Organizer 選擇Devices -> 選中的手機 -> 點擊手機名稱左邊的箭頭 會等到以下圖
注意對比一下紅色框框內容,這個日誌也基本上上告訴你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文件
#import <Foundation/Foundation.h>
@interface CatchCrash : NSObject
void uncaughtExceptionHandler(NSException *exception);
@end
.m文件
#import "CatchCrash.h"
@implementation CatchCrash
void uncaughtExceptionHandler(NSException *exception)
{
// 異常的堆棧信息
NSArray *stackArray = [exception callStackSymbols];
// 出現異常的緣由
NSString *reason = [exception reason];
// 異常名稱
NSString *name = [exception name];
NSString *exceptionInfo = [NSString stringWithFormat:@"Exception reason:%@\nException name:%@\nException stack:%@",name, reason, stackArray];
NSLog(@"%@", exceptionInfo);
NSMutableArray *tmpArr = [NSMutableArray arrayWithArray:stackArray];
[tmpArr insertObject:reason atIndex:0];
//保存到本地 -- 固然你能夠在下次啓動的時候,上傳這個log
[exceptionInfo writeToFile:[NSString stringWithFormat:@"%@/Documents/error.log",NSHomeDirectory()] atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
@end
第二步:添加一個繼承自UIViewcontroller的類,取名字爲TestViewController。
第三步:註冊CatchCrash異常處理方法,在Appdelegate寫下以下代碼:
#import "AppDelegate.h"
#import "CatchCrash.h"
#import "TestViewController.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
//註冊消息處理函數的處理方法
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
TestViewController *testVc = [[TestViewController alloc] init];
self.window.rootViewController = testVc;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
第四部:在TestViewController的Xib上面添加一個按鈕並給其添加一個單擊事件,TestViewController.m文件中有以下代碼:
#import "TestViewController.h"
@interface TestViewController ()
@end
@implementation TestViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - 單擊事件
- (IBAction)crashTapped:(id)sender
{
//常見異常1---不存在方法引用
// [self performSelector:@selector(thisMthodDoesNotExist) withObject:nil];
//常見異常2---鍵值對引用nil
// [[NSMutableDictionary dictionary] setObject:nil forKey:@"nil"];
//常見異常3---數組越界
[[NSArray array] objectAtIndex:1];
//常見異常4---memory warning 級別3以上
// [self performSelector:@selector(killMemory) withObject:nil];
//其餘你們去想吧
}
#pragma mark - custom method
- (void) killMemory
{
for (int i = 0; i < 300; i ++)
{
UILabel *tmpLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 200)];
tmpLabel.layer.masksToBounds = YES;
tmpLabel.layer.cornerRadius = 10;
tmpLabel.backgroundColor = [UIColor redColor];
[self.view addSubview:tmpLabel];
}
}
@end
運行代碼:能夠看到閃退,導出error日誌,咱們能夠看到:
Exception reason:NSRangeException
<span style="color:#FF0000;">Exception name:*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds for empty array</span>
Exception stack:(
0 CoreFoundation 0x2f2edfeb <redacted> + 154
1 libobjc.A.dylib 0x39b66ccf objc_exception_throw + 38
2 CoreFoundation 0x2f224a89 <redacted> + 176
<span style="color:#FF0000;"> 3 TestCrash 0x000e8077 -[TestViewController crashTapped:] + 126</span>
4 UIKit 0x31b3f057 <redacted> + 90
5 UIKit 0x31b3eff7 <redacted> + 30
6 UIKit 0x31b3efd1 <redacted> + 44
7 UIKit 0x31b2a737 <redacted> + 374
8 UIKit 0x31b3ea4f <redacted> + 590
9 UIKit 0x31b3e721 <redacted> + 528
10 UIKit 0x31b396eb <redacted> + 758
11 UIKit 0x31b0e8ed <redacted> + 196
12 UIKit 0x31b0cf97 <redacted> + 7102
13 CoreFoundation 0x2f2b925b <redacted> + 14
14 CoreFoundation 0x2f2b872b <redacted> + 206
15 CoreFoundation 0x2f2b6f1f <redacted> + 622
16 CoreFoundation 0x2f221f0f CFRunLoopRunSpecific + 522
17 CoreFoundation 0x2f221cf3 CFRunLoopRunInMode + 106
18 GraphicsServices 0x3417a663 GSEventRunModal + 138
19 UIKit 0x31b6d16d UIApplicationMain + 1136
20 TestCrash 0x000e810d main + 116
21 libdyld.dylib 0x3a073ab7 <redacted> + 2
)