WKCrashSDK - crash拦截工具

栏目: IOS · 发布时间: 5年前

内容简介:由于线上始终出现部分未知原因崩溃问题,遂遵循网易出的crash拦截机制,自实现了一个crash拦截工具,现已上线运行数月,累计拦截闪退···总之很多啦···原理网上已有很多文章阐述,这里推荐几个链接。

由于线上始终出现部分未知原因崩溃问题,遂遵循网易出的crash拦截机制,自实现了一个crash拦截工具,现已上线运行数月,累计拦截闪退···总之很多啦···

WKCrashSDK - crash拦截工具

实现原理

原理网上已有很多文章阐述,这里推荐几个链接。

网易iOS App运行时Crash自动防护实践 黑魔法教你让iOS APP防住Crash

优势:

  • 封装完善,使用方便,仅需将文件导入项目即可生效。
  • 具备debug期crash发生的UI层级提示。
  • 可和线上接口配合实现实时开关操作。
  • 可自定crashinfo上传地点(我司是直接上传到bugly搜集)
  • 经过实际测试,已在我司多个线上APP实测有效,暂未发现有什么奇怪的问题。

项目要点

其实从上述原理文章以及能够了解基本的实现逻辑,只是在实现过程中也遇到了不少的坑。下面就和大家分享一下一些实现过程的坑以及为了满足我司需求拓展的一些功能点。

  • KVO

这里划重点

1、拦截KVO时,存在部分三方库的不能拦截,以及系统的相机相册无需拦截,否则会出现无效的crash提示,在我的项目已经进行了白名单过滤。如果用了一些特殊的三方,可能在使用此 工具 时,需要收录一下,避免无效的crashinfo被收集。

//白名单主要针对观察者,因为被观察者很有可能是系统类,所以只能针对观察者处理,如果拦截到系统的观察者,则记录入白名单
+ (NSArray *)kvoWhiteList
{
    static NSArray *whiteList = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        whiteList = @[@"WKKVOProxy",//自己的
                      @"RACKVOProxy",//RAC的
                      @"BLYSDKManager",//bugly的
                      @"_YYTextKeyboardViewFrameObserver",//YYKit的
                      //相册相关
                      @"PLManagedAlbum",
                      @"AVCapturePhotoOutput",
                      @"AVCaptureStillImageOutput",
                      //3.2.9添加 拍照相关
                      @"AVCaptureSession",
                      @"PLPhotoStreamAlbum",
                      @"AVKVODispatcher",
                      @"PLCloudSharedAlbum",
                      @"AVPlayerPropertyCache",
                      ];//@"AVCaptureFigVideoDevice"
    });
    return whiteList;
}
复制代码

2、对KVO的拦截,需使用递归锁保证线程安全。

wk_pthread_mutex_init_recursive(&_lock,true);
        pthread_mutex_lock(&_lock);
        pthread_mutex_unlock(&_lock);
复制代码
  • Zombie

划重点

在有僵尸对象造成崩溃时,实际是将其数据置为空,但是并不释放它,然后将其isa指向一个可接受任何方法的中转类中,以此来拦截掉崩溃。为了统一处理crash上报,在这里用了动态类创建传递类型信息的方式。并且.m文件需要使用 MRC ,在编译处添加-fno-objc-arc即可。

NSString *className = NSStringFromClass(selfClass);
        NSString *zombieClassName = [@"WKZombie_" stringByAppendingString: className];//这一步很重要,动态生成类,如果被僵尸,则可以得知实际是哪个类产生了僵尸指针 导致崩溃
        Class zombieClass = NSClassFromString(zombieClassName);
        if(!zombieClass) {
            zombieClass = objc_allocateClassPair([WKZombieStub class], [zombieClassName UTF8String], 0);
        }
        objc_destructInstance(self);//销毁实例 相关信息 内存不释放
        object_setClass(self, zombieClass);
        instanceList.size();
        if (instanceList.size() >= maxCount) {
            id object = instanceList.front();
            instanceList.pop_front();
            free(object);
        }
        instanceList.push_back(self);
复制代码
  • Container

在拦截NSArray以及NSDictionary的系列方法时,需要注意一下它们的实现方式是类簇实现,需要找到它们真实的类来拦截才有效。

swizzling_exchangeMethod(objc_getClass("__NSArray0"), @selector(objectAtIndex:), @selector(emptyArray_objectAtIndex:));
swizzling_exchangeMethod(objc_getClass("__NSArrayI"), @selector(objectAtIndex:), @selector(arrayI_objectAtIndex:));
swizzling_exchangeMethod(objc_getClass("__NSSingleObjectArrayI"), @selector(objectAtIndex:), @selector(singleObjectArrayI_objectAtIndex:));
复制代码

划重点

在对NSMutablArray拦截时,需要特别注意其objectAtIndex的方法,需得在遵守MRC的文件下拦截,否则会在iOS8上弹出键盘时,APP进入后台产生崩溃。是必现的。所以在工具中 这个方法是单独放到一个文件里面hook的,然后在编译处为此文件添加-fno-objc-arc。

  • UI层级提示信息

在Debug模式下,当拦截到crash时,会出现UI层级的提示,如下图:

WKCrashSDK - crash拦截工具

点击按钮可以查看具体的崩溃信息,如下图

WKCrashSDK - crash拦截工具

前面title表示为崩溃的类型,后面数字为拦截的次数。

再次点击cell可定位崩溃的文件、对应方法名、最近一次崩溃发生的时间以及在本机上这个崩溃发生的次数。

WKCrashSDK - crash拦截工具
WKCrashSDK - crash拦截工具

大家可能也注意到了Crash的按钮是可以随意拖动,以及根据你进入的大类型不同来变更提示信息的。一个可有可无的小优化~

  • CrashInfo上报

CrashInfo的收集,我们只需要关注 WKCrashReport 类,去实现它的一个代理即可。

@protocol WKCrashReportDelegate <NSObject>

- (void)handleCrashInfo:(WKCrashModel *)model type:(NSString *)type;

@end
复制代码

返回的两个参数:WKCrashModel 以及 NSString type其功用如下:

WKCrashModel
@interface WKCrashModel : NSObject
@property (nonatomic, strong) NSString * clasName; //产生crash的类名
@property (nonatomic, strong) NSString * msg; //could be 方法名,或者其他有效信息
@property (nonatomic, strong) NSArray  * threadStack;//crash时的堆栈信息
@property (nonatomic, assign) NSTimeInterval time;//crash时间
@property (nonatomic, strong, readonly) NSString * deviceType;//设备信息
@property (nonatomic, strong, readonly) NSString * systemVersion;//系统版本
@end
复制代码

NSString type 其返回值可能有UnrecognizedSelector,KVO,Container,Timer,NotificationCenter,Null,String,Zombie 分别代表八种拦截的crash类型

PS:如有特殊需求可自行扩充

使用方式

Demo地址

进入Demo地址找到WKCrashManagerDemo里面的WKCrashSDK文件夹,拖入项目即可。 后续我会抽空将其加入cocoapods豪华午餐~

注:如从Demo中直接拖入,则默认开启除了Zomie拦截外的其他7种类型的crash拦截。如需自定义请查看WKCrashManager的实现文件。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

个体与交互

个体与交互

Ken Howard、Barry Rogers / 贾永娜、张凯峰 / 机械工业出版社华章公司 / 2012-3-20 / 45.00元

对敏捷软件开发的关注重点,通常都集中在“机制”方面,即过程和工具。“敏捷宣言”认为,个体与交互的价值要高于过程和工具,但这一点很容易被遗忘。在敏捷开发中,如果你重新将注意力放在人的方面,将会收获巨大利益。 本书展示了如何解决敏捷团队在实际项目中遭遇的问题。同时,本书也是很有实用价值的敏捷用户指南,其中包含的故事、最佳实践方法、经验以及技巧均可应用到实际项目当中。通过逐步实践,你将学会如何让团......一起来看看 《个体与交互》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具