前言
当一个iOS应用程序崩溃时,系统会创建一份crash日志保存在设备上。这份crash日志记录着应用程序崩溃时的信息,通常包含着每个执行线程的栈调用信息(低内存闪退日志例外),对于开发人员定位问题很有帮助。
为保障线上 App 的用户体验,我们一般都会对线上 App 的 crash 率做实时监控,一旦检测到 spike,可以即刻调查原因,但这一切的前提是 crash 日志能够准确上报。
crash 日志上报有两个难点:
crash handler 安装之前的代码要绝对稳定如果日志采集器还没成功启动就 crash 了,自然什么日志也无法采集到。这一点并没有太多技巧可言,只能严格限制 handler 启动之前可以执行的代码。 App 无限循环 crash 时上报
crash 日志上报时,会发送网络请求,如果请求成功之前 App 又发生 crash 该如何处理?用户甚至会陷入无限循环的 crash 中。
这篇文章介绍下出现第二种情况时,如何准确上报 crash 日志。
首先我们需要一种比较可靠的方式,可以在 app 启动时判断上次是否发生了启动 crash。介绍一个可行的思路。
如何检测连续闪退
连续闪退包含两个元素,闪退和连续。只有这两个元素同时具备时,才会影响我们的日志上传。闪退的定义可以简单为
app crash 时间 - app 启动时间 <= 5s (或者其他 threshold)
连续的定义为,至少接连出现两次或者以上。一般 2 次就够了,很多时候用户连续经历两次闪退,就会放弃尝试。
我们可以通过记录若干个特殊的时间点 timestamp 来试图还原 App crash 场景下的生命周期。
App 启动 timestamp,定义为 launchTsApp 每次启动时,记录当前时间,写入时间数组。 App crash timestamp,定义为 crashTs
App 每次启动时,通过 crash 采集库,获取上次 crash report 的时间戳,写入时间数组。 App 正常退出 timestamp,定义为 terminateTs
App 在接收到 UIApplicationWillTerminateNotification 通知时,记录当前时间戳,写入时间数组。注意,还有很多种 App 退出行为的时间戳是无法被准确记录的。
之所以要记录 terminateTs,是为了排除一种特殊情况,即用户启动 App 之后立即手动 kill app。如果我们正确记录了上面三个时间戳,那么我们可以得到一个与 App crash 行为相关的时间线。比如:
launchTs => crashTs => launchTs => terminateTs
或者
launchTs => launchTs => launchTs
或者
launchTs => crashTs => launchTs => crashTs => launchTs
请自行脑洞上面三种时间线的行为特征。很明显,第三种时间线看上去是连续 crash 了两次。我们只需要加上时间间隔判断,就能得知是否为连续两次闪退了。注意,如果两个 crashTs 之间如果存在 terminateTs,则不能被认为是连续闪退。检测代码比较简单,我就不贴了。










