iOS 之獲取崩潰日誌
為了更好的維護iosAPP,處理程式崩潰是必需要做的,那麼如何收集使用者使用時出現的崩潰呢,基本的方法如下:
1.上傳appStore的app,可以通過iTunes Stroe獲取
2.利用Xcode獲取。
3. Crashlytics,Hockeyapp ,友盟,Bugly 等等。
4.通過iOS SDK中提供了一個現成的函式 NSSetUncaughtExceptionHandler 用來做異常處理
利用NSSetUncaughtExceptionHandler,當程式異常退出的時候,可以先進行處理,然後做一些自定義的動作,並通知開發者,是大多數軟體都選擇的方法。下面就介紹如何在iOS中實現:
第一步:建立崩潰獲取類crash
.h檔案
@interface Crash : NSObject
//// 崩潰時的回撥函式
void uncaughtExceptionHandler(NSException *exception);
@end
.m檔案:
#import "Crash.h"
@implementation Crash
void uncaughtExceptionHandler(NSException *exception){
NSArray *stackArry= [exception callStackSymbols];
NSString *reason = [exception reason];
NSString *name = [exception name];
NSString *exceptionInfo = [NSStringstringWithFormat:@"Exception name:%@\nException reatoin:%@\nException stack :%@",name,reason,stackArry];
NSLog(@"%@",exceptionInfo);
//儲存到本地沙盒中
[exceptionInfo writeToFile:[NSStringstringWithFormat:@"%@/Documents/eror.log",NSHomeDirectory()] atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
@end
第二步在Appdelegate中註冊訊息方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
//註冊訊息處理函式的處理方法
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
// 傳送崩潰日誌
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *dataPath = [path stringByAppendingPathComponent:@"Exception.txt"];
NSData *data = [NSData dataWithContentsOfFile:dataPath];
if (data != nil) {
[self sendExceptionLogWithData:data path:dataPath];
}
}
第三步:崩潰日誌發動到伺服器
#pragma mark -- 傳送崩潰日誌
- (void)sendExceptionLogWithData:(NSData *)data path:(NSString *)path {
AFHTTPSessionManager *manager = [AFHTTPSessionManagermanager];
manager.requestSerializer.timeoutInterval = 5.0f;
//告訴AFN,支援接受 text/xml 的資料
[AFJSONResponseSerializerserializer].acceptableContentTypes = [NSSetsetWithObject:@"text/plain"];
NSString *urlString = @"後臺地址";
[manager POST:urlString parameters:nilconstructingBodyWithBlock:^(id<AFMultipartFormData> _NonnullformData) {
[formData appendPartWithFileData:data name:@"file"fileName:@"Exception.txt" mimeType:@"txt"];
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
// 刪除檔案
NSFileManager *fileManger = [NSFileManagerdefaultManager];
[fileManger removeItemAtPath:path error:nil];
} failure:^(NSURLSessionDataTask * _Nonnull task, NSError* _Nonnull error) {
}];
}
========================
#import <Foundation/Foundation.h>
@interface MyUncaughtExceptionHandler : NSObject
+ (void)setDefaultHandler;
+ (NSUncaughtExceptionHandler *)getHandler;
+ (void)TakeException:(NSException *) exception;
@end
****************
#import "MyUncaughtExceptionHandler.h"
#import "AFNetworking.h"
// 沙盒的地址
NSString * applicationDocumentsDirectory() {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES)lastObject];
}
// 崩潰時的回撥函式
void UncaughtExceptionHandler(NSException * exception) {
NSArray * arr = [exception callStackSymbols];
NSString * reason = [exceptionreason]; // // 崩潰的原因 可以有崩潰的原因(陣列越界,字典nil,呼叫未知方法...) 崩潰的控制器以及方法
NSString * name = [exception name];
NSString * url = [NSStringstringWithFormat:@"========異常錯誤報告========\nname:%@\nreason:\n%@\ncallStackSymbols:\n%@",name,reason,[arrcomponentsJoinedByString:@"\n"]];
NSString * path = [applicationDocumentsDirectory()stringByAppendingPathComponent:@"Exception.txt"];
// 將一個txt檔案寫入沙盒
[url writeToFile:pathatomically:YESencoding:NSUTF8StringEncodingerror:nil];
}
@implementation MyUncaughtExceptionHandler
// 沙盒地址
- (NSString *)applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES)lastObject];
}
+ (void)setDefaultHandler {
NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
}
+ (NSUncaughtExceptionHandler *)getHandler {
returnNSGetUncaughtExceptionHandler();
}
+ (void)TakeException:(NSException *)exception {
NSArray * arr = [exception callStackSymbols];
NSString * reason = [exception reason];
NSString * name = [exception name];
NSString * url = [NSStringstringWithFormat:@"========異常錯誤報告========\nname:%@\nreason:\n%@\ncallStackSymbols:\n%@",name,reason,[arrcomponentsJoinedByString:@"\n"]];
NSString * path = [applicationDocumentsDirectory()stringByAppendingPathComponent:@"Exception.txt"];
[url writeToFile:pathatomically:YESencoding:NSUTF8StringEncodingerror:nil];
}
//============
//在appledelegate匯入標頭檔案加上一個異常捕獲監聽,用來處理程式崩潰時的回撥動作 在這裡也要判斷一下之前有沒有崩潰日誌 如果有傳送給伺服器
//
//- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//#pragma mark -- 崩潰日誌
// [MyUncaughtExceptionHandler setDefaultHandler];
// // 傳送崩潰日誌
// NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// NSString *dataPath = [path stringByAppendingPathComponent:@"Exception.txt"];
// NSData *data = [NSData dataWithContentsOfFile:dataPath];
// if (data != nil) {
// [self sendExceptionLogWithData:data path:dataPath];
// }
//
// return YES;
//}
//
//#pragma mark -- 傳送崩潰日誌
//- (void)sendExceptionLogWithData:(NSData *)data path:(NSString *)path {
//
// AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// manager.requestSerializer.timeoutInterval = 5.0f;
// //告訴AFN,支援接受 text/xml 的資料
// [AFJSONResponseSerializer serializer].acceptableContentTypes = [NSSet setWithObject:@"text/plain"];
// NSString *urlString = @"後臺地址";
//
// [manager POST:urlString parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
// [formData appendPartWithFileData:data name:@"file" fileName:@"Exception.txt" mimeType:@"txt"];
// } success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
// // 刪除檔案
// NSFileManager *fileManger = [NSFileManager defaultManager];
// [fileManger removeItemAtPath:path error:nil];
//
// } failure:^(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error) {
//
//
// }];
//
//}
@end