内容字号:默认大号超大号

段落设置:段首缩进取消段首缩进

字体设置:切换到微软雅黑切换到宋体

2.崩溃监控

2018-06-08 19:44 出处:清屏网 人气: 评论(0

在咱们日常开发中,以及测试妹纸在进行测试中,我们的应用时不时的会因为编码不当等问题直接闪退。如果是在我们日常开发中还好,我们可以直接在Xcode的控制台上看到崩溃堆栈,看着堆栈就能Debug了,但是如果是在测试妹纸测试中的话就比较麻烦了,我们需要她们能复现出崩溃的路径,然后自己连上Xcode,编译运行,把崩溃堆栈复现在Xcode的控制台上才能进行Debug。

这种心情就好比“你带着老婆,出了城,吃着火锅还唱着歌,突然就被麻匪劫了”。这种心情就好比“本来 今巅 高高兴兴,泥为什么莫要说这种话。蓝瘦!香菇!”

为了不被麻匪劫,为了今巅高高兴兴,我们需要对崩溃进行监控,最好只要应用一崩溃,咱们就能够将崩溃现场给在本地保存好,等开发或者测试下一次打开就能展示给他们看。方便我们快速定位问题的原因。

那么,我们要如何才能对崩溃进行监控呢?其实应用崩溃无外乎两种,一种是未捕获的异常 UncaughtException ,还有一种就是底层信号崩溃,类似 SIGABRTSIGSEGV 等。换句话说就是一种是Objective-C代码的崩溃,还有一种就是C,C++代码的崩溃。

Swift中比较特殊,比如类似 NSArray 这种从Objective-C桥接过来的类崩溃的话会抛出一个未捕获的异常崩溃,但是像 Array 这种的Swift自己的类就会抛出一个底层信号的崩溃。

OK,接下来让我们来看看如何监控未捕获的异常崩溃以及底层信号崩溃。

该章节涉及到的开源库 CrashEye ,可以先通过 https://github.com/zixun/CrashEye 下载下来,由于文章的篇幅限制,文章中只会列出关键代码,因此大家可以一边对照开源代码一边阅读该章节,更方便理解。

2.1 监控未捕获异常崩溃

NSSetUncaughtExceptionHandler

Apple很贴心的为我们提供了处理未捕获异常崩溃的API,他们就是 NSSetUncaughtExceptionHandlerNSGetUncaughtExceptionHandler

NSSetUncaughtExceptionHandler 的文档是这么写的:

Sets the top-level error-handling function where you can perform last-minute logging before the program terminates.

言下之意就是在程序崩溃之前,只要你设置了这个API,程序就会在崩溃的最后一刻给你机会做日志记录。这正是我们想要的。我们可以创建一个崩溃监控类 CrashEye :

public class CrashEye: NSObject {

}

思考崩溃监控类的架构

我们的崩溃监控类需要处理两类监控,一类就是未捕获异常崩溃,还有一类是底层信号崩溃。在Swift这两类崩溃的回调都是C语言层级的API,比如 NSSetUncaughtExceptionHandler :

public func NSSetUncaughtExceptionHandler(_: (@escaping @convention(c) (NSException) -> Swift.Void)?)

我们可以看到 @convention(c) 关键字,它是用来修饰 Swift 中的函数类型,调用C语言函数的时候,可以传入修饰过@convention(c) 的函数类型,系统会自动匹配到C语言函数参数中的函数指针。所以在这里,Swfit一般传入的都是一个全局的闭包变量,或者一个类中的static闭包变量。因此我们可以试试将我们的 CrashEye 设计成不需要初始,全部类方法实现,外部调用一个 开始监控 的方法,设置好监听的delegate就可以开始工作了。

当然,为了方便Crash监控的扩展,这里的监控回调也是设计成delegate的weak化数组,具体实现这里不再赘述,可以参考日志监控章节中监控print日志中的描述,或者阅读源码。

实现未捕获异常崩溃监控

好了,咱们开始实现未捕获异常崩溃监控,首先需要实现我们调用的 NSSetUncaughtExceptionHandler 方法需要传入的Handler静态闭包变量:

private static let RecieveException: @convention(c) (NSException) -> Swift.Void = {
    (exteption) -> Void in

    guard CrashEye.isOpen == true else {
        return
    }

    let callStack = exteption.callStackSymbols.joined(separator: "\r")
    let reason = exteption.reason ?? ""
    let name = exteption.name
    let appinfo = CrashEye.appInfo()


    let model = CrashModel(type:CrashModelType.exception,
                           name:name.rawValue,
                           reason:reason,
                           appinfo:appinfo,
                           callStack:callStack)
    for delegate in CrashEye.delegates {
        delegate.delegate?.crashEyeDidCatchCrash(with: model)
    }
}

当收到Exception的crash后,我们会提取异常信息,包装成一个model,然后传给delegate数组通知给外部。然后在我们的 open 方法中把他设置上:

private class func open() {
    guard self.isOpen == false else {
        return
    }
    CrashEye.isOpen = true
    NSSetUncaughtExceptionHandler(CrashEye.RecieveException)
}

基本功能已经完成,现在我们能监控系统抛出的未捕获的异常啦,终于可以带着老婆吃着火锅唱着歌去了,可是火锅还没热,就有同事跑过来说:

“哥们,不带你这么玩滴!”

“咋的了,麻匪又来了?”

“那倒不是,就是做咱App的隔壁老王那团队,他们也设置了NSSetUncaughtExceptionHandler”

“然后勒?”

“然后你也设置了NSSetUncaughtExceptionHandler,人家的方法比你早调用,就被你顶掉了,他们现在啥数据都拿不到咧!”

“...”

好办,咱不是还有一个 NSGetUncaughtExceptionHandler ,设置之前把他们的存起来就可以了。说改就改,咱程序员不都随身携带电脑么:

放一个文件内全局的exceptionHandler:

var app_old_exceptionHandler:(@convention(c) (NSException) -> Swift.Void)? = nil

把隔壁老王的UncaughtExceptionHandler存起来:

private class func open() {
    guard self.isOpen == false else {
        return
    }
    CrashEye.isOpen = true

    app_old_exceptionHandler = NSGetUncaughtExceptionHandler()
    NSSetUncaughtExceptionHandler(CrashEye.RecieveException)
}

然后在 RecieveException 闭包变量中的最前面加入以下代码,

if (app_old_exceptionHandler != nil) {
    app_old_exceptionHandler!(exteption);
}

这样的话,有隔壁老王,就先调用隔壁老王,隔壁老王开心了,咱也开心了。

2.2 监控底层信号崩溃

通过上一章节我们可以监控系统抛出的未捕获的异常crash,但是我们日常开发中经常会出现类似 SIGABRTSIGSEGV 之类的Signal的crash,他们是啥呢?

Signal

我们随便点一个signal变量进去可以发现这些都定义在 Darwin/sys/signal 目录下(Objective-C的话定义在 usr/include/sys/signal.h 下), Darwin 就是iOS操作系统的内核,可见,这些信号都是底层操作系统抛出的信号。Darwin定义了很多崩溃信号,这里我们简单介绍几个常见的信号的意思:


分享给小伙伴们:
本文标签: iOS开发

相关文章

发表评论愿您的每句评论,都能给大家的生活添色彩,带来共鸣,带来思索,带来快乐。

CopyRight © 2015-2016 QingPingShan.com , All Rights Reserved.

清屏网 版权所有 豫ICP备15026204号