"只有那一台手机会出"
每个团队都有这么一个 bug:在某一台手机上稳定复现,别人的机器上一次都不出,而且任何“是不是用户操作有问题”的解释都站不住。
它几乎从来不是玄学,几乎总是某项没人列举过的设备状态差异。下面这份清单,大致按“最后被证明是答案”的频率排序。
1. 系统版本
第一个该查、也最常被跳过的一项,因为所有人都觉得自己已经知道了。小版本改变行为的频率比大家以为的高:WebKit、网络栈、键盘、后台调度,以及一个进程能拿到的内存上限。
要拿到准确的构建号,不是“iOS 17”。17.4 和 17.4.1 是两套软件。
2. 剩余存储
磁盘快满的设备会以各种“看起来完全不像存储问题”的方式出问题:
- 写入失败,取决于错误怎么处理,有时是静默失败
- 缓存刚写进去就被回收,于是缓存看起来完全没生效
- 装包装到一半失败
- 系统更激进地终止后台进程
问一下剩余空间。低于两三个 GB,就把它当首要嫌疑。
3. 发热状态
发烫的手机会降频。设备如果套着壳、放在阳光下的桌面上,或者已经连续采集了二十分钟,它就是一台比同型号凉机更慢的机器。
特征是:会话跑得越久问题越严重,手机放着晾十分钟之后又好了。
4. 电池健康
老电池无法像新电池那样提供峰值电流,iOS 会限制性能以避免意外关机。一台容量 78%、循环 900 次的设备,和同型号 100% 的那台不是同一台机器。
读容量和循环次数,别停留在“电池看着还行”。
5. 配置描述文件
没人查的那一项,也是能产生最诡异结果的那一项。描述文件可以装根证书、把流量导进 VPN、关掉某个系统能力,或者把设备纳入一个自带策略的 MDM。
如果某台设备上有一个你并不知道的 VPN 描述文件,那这台设备上所有和网络相关的症状都不可信 —— 地区判断不同、延迟不同、别处都成功的请求在这里失败。
6. 语言、地区与 Locale
数字格式、日期解析、文字方向、排序规则,以及界面上每一个字符串的长度。“只在德语下布局崩掉”是一类真实存在的 bug;“只在使用另一种历法的地区解析日期失败”也是。
7. 辅助功能设置
更大字体、粗体文本、减弱动态效果、降低透明度、增强对比度、旁白。每一项都会改变布局或行为,而且在真实用户里都足够常见 ——“只在那台手机上”经常意味着“只在动态字体拉到最大时”。
8. 时间与时区
手动设置过时钟的设备,或者处在日期变更线另一侧的时区,会把你日期处理里所有的差一错误全暴露出来。缓存过期、令牌刷新、“今天”的内容,都是常见受害者。
9. 网络
不只是 Wi-Fi 和蜂窝的区别。强制门户认证、纯 IPv6 的运营商、企业 DNS、应用级 VPN、低数据模式。光是低数据模式就会关掉后台刷新、降低视频码率,行为差异很大,而设备上看不出任何异常。
10. 机型与内存
3 GB 内存的手机拿到的内存配额比 8 GB 的小。在旗舰上没事的代码,在低配机型上会被 jetsam 杀掉 —— 表现出来是一份没有异常信息的崩溃报告。屏幕尺寸和安全区内边距也归在这一类。
怎么执行
- 动手之前先把设备状态记下来。 iOS 构建号、存储、电池健康与循环次数、已装描述文件、地区语言、辅助功能设置。一半的排查在这一步就结束了。
- 找出一个差异。 和一台不复现的设备逐项对比。
- 在别处复现这个差异。 如果你怀疑是存储,就去把另一台设备填满。这一步把猜想变成结论。
- 然后再去读日志和采集结果 —— 此时你已经知道要找什么了。
清单之外的那一种
有时候答案真的在用户的数据里。一个有五万条记录的账号、一个损坏的本地数据库、一次从两年前的版本迁移到一半的状态。当所有设备属性都对得上、bug 却跟着人而不是跟着手机走时,去看 App 存了什么 —— 答案在沙盒里。
