iOS防crash框架+自动上报到企业微信

375 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

此框架只能捕获基础类型(详细看注意事项)导致的崩溃,捕获之后不会闪退,也不会上报bugly,但是bug需要自己排查,所以上传崩溃日志到企业微信并@相应开发人员查看。

集成AvoidCrash

pod 'AvoidCrash', '~> 2.5.2'

在AppDelegate的application:didfinish里添加

[AvoidCrash makeAllEffective];
[AvoidCrash setupNoneSelClassStringsArr:@[@``"NSString"``, @``"NSNull"``, @``"NSNumber"``, @``"NSDictionary"``, @``"NSArray"``]];

[[NSNotificationCenter defaultCenter]addObserver:self selector:``@selector``(dealwithCrashMessage:) name:AvoidCrashNotification object:nil];
- (void)dealwithCrashMessage:(NSNotification *)note {
    //注意:所有的信息都在userInfo中
    //你可以在这里收集相应的崩溃信息进行相应的处理(比如传到自己服务器)
    NSDictionary *info = note.userInfo;
     
    /// 上报企业微信
    [JXWechatBotRequest uploadCrashInfo:info];
}

JXWechatBotRequest这个类实现上报企业微信机器人@相应开发人员

- (instancetype)initWithText:(NSString *)text {
    self = [super init];
    if (self) {
        /// 自己替换企业微信名称和手机号
        self.params = @{@"msgtype":@"text",
                        @"text":@{
                            @"content":text,
                            @"mentioned_list":@[@""],
                            @"mentioned_mobile_list":@[@""]
                        }
        };
    }
    return self;
}
 
- (NSString *)requestUrl {
///替换成自己的webhook链接
    return @"";
}
 
- (YTKRequestMethod)requestMethod {
    return YTKRequestMethodPOST;
}
 
- (id)requestArgument {
    return self.params;
}
 
- (YTKRequestSerializerType)requestSerializerType {
    return YTKRequestSerializerTypeJSON;
}
 
- (YTKResponseSerializerType)responseSerializerType {
    return YTKResponseSerializerTypeHTTP;
}

/// 打包日志
+ (void)uploadDDLogInfo:(void(^)(NSString *url))completeBlock {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        NSData *zipData = [JXCocoaZipManager jxCompressedFileWithLogs];
        if (zipData) {
            [[JXBKUpload shareManager]aliyunUploadSingleFile:zipData suffix:@"zip" progress:^(int64_t progressBytes, int64_t totalProgressBytes) {
                     
            } success:^(BOOL success, NSString *url) {
                dispatch_async_on_main_queue(^{
                    if (completeBlock) {
                        completeBlock(url);
                    }
                });
            }];
        } else {
            dispatch_async_on_main_queue(^{
                if (completeBlock) {
                    completeBlock(nil);
                }
            });
        }
    });
}
 
+ (void)uploadCrashInfo:(NSDictionary *)info {
    [self uploadDDLogInfo:^(NSString *url) {
        NSArray *callStack = info[@"callStackSymbols"];
        NSDictionary *extraInfo = @{@"currentControllers":[JXBKRouter getCurrentVC].navigationController.viewControllers};
         
        NSString *errorReason = [NSString stringWithFormat:@"【ErrorReason】%@\n【ErrorPlace】%@\n【DefaultToDo】%@\n【ErrorName】%@\n【extraInfo】%@", info[@"errorReason"], info[@"errorPlace"], info[@"defaultToDo"], info[@"errorName"], extraInfo];
 
        DDLogInfo(@"***crash***:%@", [NSThread currentThread]);
        DDLogInfo(@"***crash***:%@", errorReason);
        DDLogInfo(@"***crash***:%@", callStack);
        
        NSString *sysVersion = [[UIDevice currentDevice] systemVersion];
        NSString *deviceModel = [[UIDevice currentDevice] model];
        NSString *env;
#ifdef DEBUG
        env = @"Debug";
#else
        env = @"Release";
#endif
         
        NSString *content = [NSString stringWithFormat:@"%@\n【日志】%@\n【设备型号】%@-%@\n【环境】%@", errorReason, url, deviceModel, sysVersion, env];
        JXWechatBotRequest *request = [[JXWechatBotRequest alloc]initWithText:content];
        [request startWithCompletionBlockWithSuccess:^(__kindof YTKBaseRequest * _Nonnull request) {
             
        } failure:^(__kindof YTKBaseRequest * _Nonnull request) {
             
        }];
    }];
}

注意事项

这个框架的适用范围是下表,像OOM、APP卡死等无法捕获

类名适用范围
类名适用范围
NSString1. - (unichar)characterAtIndex:(NSUInteger)index2. - (NSString *)substringFromIndex:(NSUInteger)from3. - (NSString *)substringToIndex:(NSUInteger)to {4. - (NSString *)substringWithRange:(NSRange)range {5. - (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement6. - (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement options:(NSStringCompareOptions)options range:(NSRange)searchRange7. - (NSString *)stringByReplacingCharactersInRange:(NSRange)range withString:(NSString *)replacement
NSMutableString1. 由于NSMutableString是继承于NSString,所以这里和NSString有些同样的方法就不重复写了2. - (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)aString3. - (void)insertString:(NSString *)aString atIndex:(NSUInteger)loc4. - (void)deleteCharactersInRange:(NSRange)range
NSMutableDictionary1. - (void)setObject:(id)anObject forKey:(id)aKey2. - (void)removeObjectForKey:(id)aKey
NSMutableAttributedString1.- (instancetype)initWithString:(NSString *)str2.- (instancetype)initWithString:(NSString *)str attributes:(NSDictionary<NSString *,id> *)attrs
NSMutableArray1. - (id)objectAtIndex:(NSUInteger)index2. - (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx3. - (void)removeObjectAtIndex:(NSUInteger)index4. - (void)insertObject:(id)anObject atIndex:(NSUInteger)index5. - (void)getObjects:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range
NSDictionary1. NSDictionary的快速创建方式 NSDictionary *dict = @{@"frameWork" : @"AvoidCrash"}; //这种创建方式其实调用的是2中的方法2. +(instancetype)dictionaryWithObjects:(const id  _Nonnull __unsafe_unretained *)objects forKeys:(const id  _Nonnull __unsafe_unretained *)keys count:(NSUInteger)cnt
NSAttributedString1.- (instancetype)initWithString:(NSString *)str2.- (instancetype)initWithAttributedString:(NSAttributedString *)attrStr3.- (instancetype)initWithString:(NSString *)str attributes:(NSDictionary<NSString *,id> *)attrs
NSArray1. NSArray的快速创建方式 NSArray *array = @[@"chenfanfang", @"AvoidCrash"];  //这种创建方式其实调用的是2中的方法2. +(instancetype)arrayWithObjects:(const id  _Nonnull __unsafe_unretained *)objects count:(NSUInteger)cnt3. - (id)objectAtIndex:(NSUInteger)index4. - (void)getObjects:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range