前言
大白(Baymax),迪士尼动画《超能陆战队》中的健康机器人,是一个体型胖胖的充气机器人,因呆萌的外表和善良的本质获得大家的喜爱,被称为“萌神”。
Baymax项目是为了减少开发人员在开发中一些不规范的代码编写造成的内存泄露,界面卡顿,耗电等问题而来的一个监控系统。
现在Baymax迎来了它新的功能:APP运行时Crash自动防护功能,为app的流程顺利运行保驾护航!
下面将详细介绍一下 APP运行时Crash自动修复系统 开发的目的,设计的原理以及使用的方法。
APP运行时Crash自动修复系统
Chapter 1 - 开发目的
是否存在这样的夜晚,当刚刚躺下准备美美的睡一觉的时候, 突然来一记夺命电话Call,一接起来发现是你老板!!!“小王啊,刚刚上线的X.X.X版本出问题了啊,怎么样操作会crash啊,导致新功能都无法使用了,快定位一下是什么原因,抓紧hotpatch修复一下啊!”。心里一万头草泥马呼啸而过,瞬间已经满头大汗的你却还要故作镇静地回答:“嗯,老板我马上去看看,一定努力解决问题!” 急忙打开电脑的你,知道今夜注定无眠了。
是否又存在这样的情形,你老板把大家都聚起来开了一个年初KPI目标制定会议,说到:“作为一个资深的技术团队,app性能是我们技术团队首抓的目标,其中很最要的一项就是app的崩溃率,去年我们app统计出来的崩溃率是千分之五,而我们的竞争对手的崩溃率只有万分之五,相差了10倍!今年我们要赶超他们,最起码也要和他们持平。” 你甚是赞同,但是你心里却又有点怀疑,对方的开发资源是我们的好几倍而且个个都是资深老司机,我们团队里却大多都是应届生小鲜肉,这KPI能完成么?
如果你遇到过以上的情况并且对此深表头痛的话,那么 大白健康系统–APP运行时Crash自动修复系统 将会是你的不二选择!
APP运行时Crash自动修复+捕获系统 的设计初衷,就是为了降低app的crash率。利用Objective-C语言的动态特性,采用AOP(Aspect Oriented Programming) 面向切面编程的设计思想,做到无痕植入。能够自动在app运行时实时捕获导致app崩溃的破环因子,然后通过特定的技术手段去化解这些破坏因子,使app免于崩溃,照样可以继续正常运行,为app的持续运转保驾护航。
Chapter 2 - 功能简介
APP运行时Crash自动修复系统 的主要功能,可以用一句话来简单的概括:对业务代码的零侵入性地将原本会导致app崩溃的crash抓取住,消灭掉,保证app继续正常地运行,再将crash的具体信息提取出来,实时返回给用户。
通过下面的一个小例子就可以很直观的体现出来系统的作用:
调用以下的一段代码
//test code
UIButton * testObj = [[UIButton alloc] init];
[testObj performSelector:@selector(someMethod:)];
结果肯定会导致app的崩溃,因为testObj是一个UIButton对象,而UIButton并没有实现 someMethod: 这个方法,所以向testObj发送someMethod:这个方法的时候,将会导致该方法无法在相关的方法列表里找到,最终导致app的crash。
但是通过我们的crash防护系统,调用这段代码时app并不会崩溃,同时XCode的Console如下:
可见对应的crash的信息(crash类型,原因,调用栈信息)均可以完整的打印在XCode的Console中。
说明我们的大白系统已经捕捉到了这个crash,将该crash消灭掉并且吐出来该crash的完整信息。
当然目前系统的功能并没有强大到可以把所有的crash都处理掉,不过一些常见的高频次发生的crash,系统均会针对他们一一处理。目前可以处理掉的crash类型具体有以下几种:
-
unrecognized selector crash
-
KVO crash
-
NSNotification crash
-
NSTimer crash
-
Container crash(数组越界,插nil等)
-
NSString crash (字符串操作的crash)
-
Bad Access crash (野指针)
-
UI not on Main Thread Crash (非主线程刷UI(机制待改善))
对于每种类型的crash,安全系统都采取不同的方式,进行了对应的处理。 具体的处理细节详见下章:Chapter 3 - 实现原理
Chapter 3 - 实现原理
前面已经提过,目前的安全防护系统可以覆盖到8中类型的Crash,分别为:
-
unrecognized selector crash
-
KVO crash
-
NSNotification crash
-
NSTimer crash
-
Container crash(数组越界,插nil等)
-
NSString crash (字符串操作的crash)
-
Bad Access crash (野指针)
-
UI not on Main Thread Crash (非主线程刷UI (机制待改善))
接下来将一一详细介绍这8种类型的Crash的防护的实现的具体原理:
3.1 Unrecognized Selector类型crash防护(Unrecognized Selector)
3.1.1 unrecognized selector crash 产生原因
unrecognized selector类型的crash在app众多的crash类型中占着比较大的成分,通常是因为一个对象调用了一个不属于它方法的方法导致的。
例如调用以下一段代码就会产生crash
//test code
UIButton * testObj = [[UIButton alloc] init];
[testObj performSelector:@selector(someMethod:)];
具体crash时的表现见下图:
要解决这中类型的crash,我们需要先了解清楚它产生的具体原因和流程。
3.1.2 方法调用流程
让我们看一下方法调用在运行时的过程。
runtime中具体的方法调用流程大致如下:
1.首先,在相应操作的对象中的缓存方法列表中找调用的方法,如果找到,转向相应实现并执行。
2.如果没找到,在相应操作的对象中的方法列表中找调用的方法,如果找到,转向相应实现执行
3.如果没找到,去父类指针所指向的对象中执行1,2.