0%

iOS捕获异常崩溃发送钉钉方法

由于项目最近crash率比较高,为了更好地监控线上程序包的crash,所以开发将异常崩溃捕获发送钉钉消息的功能。

异常的捕获

通过使用NSSetUncaughtExceptionHandler方法将异常捕获然后进行处理。

在Appdelegate中定义如下函数,用来处理捕获到的异常。

1
2
3
4
5
6
7
8
9
10
11
void uncaughtExceptionHandler(NSException *exception)

{
// 异常的堆栈信息
NSArray *stackArray = [exception callStackSymbols];
// 出现异常的原因
NSString *reason = [exception reason];
// 异常名称
NSString *name = [exception name];
//TODO 发送钉钉消息
}

下面是捕获异常的代码,didFinishLaunchingWithOptions方法中写入:

1
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);

到这里就可以进行异常捕获了,下面我们写一段让程序崩溃的代码进行测试

1
2
3
- (void)crashMethod{
[self performSelector:@selector(thisMthodDoesNotExist) withObject:nil];//调用一个不存在的方法。
}

到这里uncaughtExceptionHandler就可以捕获到应用的崩溃Exception了。

第三方冲突

如果项目里使用了友盟等第三方异常监控分析工具,会和我们NSSetUncaughtExceptionHandler方法冲突,导致第三方不会上传异常信息,解决方案是使用NSGetUncaughtExceptionHandler()获取到第三方捕获异常的Handler,当我们处理完异常将NSException对象传给第三方的Handler。

1
static NSUncaughtExceptionHandler *_previousHandler;//Appdelegate定义一个全局静态变量用来保存第三方的异常Handler

didFinishLaunchingWithOptions方法中在NSSetUncaughtExceptionHandler之前先保存之前的Handler:

1
2
3
// 保存第三方处理异常的handler
_previousHandler = NSGetUncaughtExceptionHandler();
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);

最后在uncaughtExceptionHandler函数最后(即我们自定义的异常处理之后),将exception回传给第三方Handler。

1
2
3
4
//将exception回传给第三方Handler
if (_previousHandler) {
_previousHandler(exception);
}

给钉钉群发送消息

#####1、首先是在钉钉群里新建一个自定义机器人,获取到机器人的webhook。详细的步骤可以看钉钉API文档:

https://open-doc.dingtalk.com/docs/doc.htm?spm=a219a.7629140.0.0.Uf9uaN&treeId=257&articleId=105735&docType=1#s1

#####2、向机器人的webhook发送post消息。

下面是用AFNetworking发送post请求的代码,注意请求参数的格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   NSDictionary *dict = @{
@"msgtype":@"text",
@"text":@{@"content":self.errorMessage?self.errorMessage:@""},
@"at":@{
@"atMobiles":self.arrayAtPhones?self.arrayAtPhones:@[],
@"isAtAll":@NO
}
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error];
AFURLSessionManager *sessionManager = [[AFURLSessionManager alloc] init];
AFJSONResponseSerializer *responseSerializer = [AFJSONResponseSerializer serializer];
responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html", @"text/plain", @"image/jpeg", nil];
sessionManager.responseSerializer = responseSerializer;
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:self.dingdingUploadUrl]];
[req setHTTPMethod:@"POST"];
[req setHTTPBody:jsonData];
//不设置会返回参数错误
[req setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[[sessionManager dataTaskWithRequest:req uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {

}]resume];

到这里就可以正常给钉钉发送消息了。纯手敲难免有手误,哪里不准确的地方请指出。

demo工程地址:https://github.com/CoderJasons/-CatchCrashTest