客户端稳定性
客户端稳定性重要性毋庸置疑。在高举用户体验第一的移动时代,稳定性就是用户体验的基线。
这里简单的介绍一下在工作中遇到的和想到的一些思路。
稳定性体系的搭建可分为业务上线前中后三个阶段
- 代码上线之前
- 代码线上运行
- 运行崩溃产生
我们这里讨论的稳定性主要是指崩溃(Crash率),不涵盖其他性能指标(滑动帧率,CPU使用率,内存使用情况等)。
关于 Crash Reports Apple官方有详细的文档Understanding and Analyzing Application Crash Reports
这里需要区别对待的是 崩溃日志的收集,不能依赖官方的日志采集(时效性)。像大厂对这方面有要求的都是自己实现崩溃日志采集并维护一个崩溃日志分析系统(符号化,业务分拣,监控报警)
稳定性线上解决方案,就不得不提热修复了。 这个至关重要,对大厂来说线上一个高频率Crash损失是致命的(对应测试覆盖关键用户操作路径)。业界主流选择是JSPatch 和 wax
稳定性防护
上线前
充分测试是上线前环节是必不可少的。尽量覆盖各种用户操作路径和数据场景,枚举正常流和异常流情况。建立完善的CI体系也是可以提升应用质量
Code Review,这个是老生常谈的一个话题。有过实习时上线代码被组内同学review的经历
将一些安全编码经验沉淀成规则,就有了静态扫描工具。如Xcode自带的Analyze,也可以自定义扫描规则严格控制上线代码逻辑质量。在CI持续集成中可以增加这样的卡口限制不安全代码集成上线
重要版本迭代进行灰度机制,发布bate版本。小范围试用,影响范围可控
线上代码运行时
安全方法
Apple Foundation
中提供的常用数据结构,部分接口是不安全的如NSMutableArray
的- (void)addObject:(ObjectType)anObject
文档说明中提及 插入nil
会导致程序出现异常进而崩溃
1 | Description |
这些不安全的接口,应该禁止调用。在组内推广使用安全的接口(实现扩展对参数进行校验)
安全气囊
基于Objective-C Runtime Programming Guide介绍中
Message Forwarding
Sending a message to an object that does not handle that message is an error. However, before announcing the error, the runtime system gives the receiving object a second chance to handle the message.
应对 unrecognized selector sent to instance/class
安全气囊实现软着陆,避免崩溃
try catch
Objective-C 中实际编程应用try catch
场景并不多。但比如NSJSONSerialization
序列化时 出现非JSON数据类型,系统还是会抛出异常让开发者处理的。
1 | If obj will not produce valid JSON, an exception is thrown. This exception is thrown prior to parsing and represents a programming error, not an internal error. You should check whether the input will produce valid JSON before calling this method by using isValidJSONObject:. |
主要还是开发者编码时的安全意识,防御式编程。使用系统API时,尽量多考虑异常情况的出现。
崩溃产生后
由于上线了有逻辑缺陷的代码导致的崩溃,可由热修复方案来实现替换。
但存在这样一种场景:由于错误数据导致的客户端崩溃。虽然回滚了服务端的发布没有新增设备的崩溃,但老设备持有了脏数据缓存导致应用启动崩溃。这个时候热修复方案就显得有点”棘手”。
- 当然可以选择热修复去掉缓存逻辑,并不是很好,至少一个版本用户不能体验到缓存带来的优化。
- 热修复也存在时机问题,热修复带有网络交互。除非阻塞式拉取最新补丁逻辑,否则无法及时修复启动崩溃
这里就有一个”安全模式”的思路:
在客户端本地产生超过阈值的崩溃时(高频),自启动或提示用户启动 安全模式逻辑。主要就是针对上述场景做的一次补救,注意 逻辑时机一定要早于任何业务处理时机
导图中枚举了常见的几种脏数据数据缓存场景,具体实现还要结合自身业务发展考虑。