本篇文章向大家分享了一个关于Fix一个随机重现的键盘issue后的思考,很有意义,感兴趣的朋友可以看一下

最近花了近一周fix了一个移动端的bug,是个很有趣的bug,大概是这样的。这是一个比较长的故事,有兴趣的可以一直看。

是一个什么样的bug

bug的表现是在一款tablet端应用使用很久之后,第一,在输入框内输入一些内容后,点击done/search,第二,然后点击页面的一些空白区域,软键盘弹出,并且光标focus在最近输入过的输入框内。

此时应用对用户行为的响应会让用户很疑惑和费解。
总结,它有如下几个特点

应用最开始是正常的,不是每次都能重现

一旦出现这个bug,在每一个存在输入框的页面都存在这个问题

重现的场景不明,目前已知是应用使用的越久越容易出现,应用一旦后台关闭病重新启动,又会消失。

如何去修复这个bug第一步 试图稳定重新

我们先是试图去找一个最小的用户journey去复现这个bug,当时运气比较好,花了大概半天时间找到了一条最小的重现路径。

不说业务背景,简单介绍下应用的页面逻辑。
我们的应用在登录之后有一个home页面,home页面存在三个tab可以滑动或者点击切换,在tab页面之上还存在一些功能菜单,其中某个功能菜单menuA可以点击跳到另一个新的带有一个输入框的页面。
页面大概如下,不是专业ux很丑勿见怪。

Fix一个随机重现的键盘issue后的思考(ReactNative)-php教程-PHP中文网

我们发现的一条可以快速重现的路径是

登录到达home页面后,反复切换三个tab多次(20次以上)

点击menuA到达一个带输入框的页面

在输入框输入数据,并点击软键盘的done

点击页面空白区域

然后软键盘就出来了。

第二步 试图从代码部分找到为什么最小场景会出现问题

找到一个最小重现路径之后,我们可以从代码里面找找为什么会出现这个问题。
因为这个bug在应用重启后没有,我们怀疑的方向就定位在render的问题,大概率是出在组件上。
我们中间有几个猜测

自己封装的input组件有问题

三个tabs的滑动组件有问题,滑动组件内的scroll view影响了RN的手势响应系统

最后发现貌似都不是,这个时候和组内另外一个同事pair,她发现在请求比较多的时候容易有问题,中间还怀疑过网络请求处理导致的。这个怀疑其实不大对,但是确实为我们找到了一条路。

我们最后发现我们所有的网络请求都在请求结果返回之前在页面出现一层蒙版mask以及一个类似web里面spinner(在RN里面是ActivityIndicator)的loading提示符号,这个部分是会影响页面render的。
而把这部分去掉(在请求到达之前不出现蒙层),这个bug就没有了,这个发现当时还是让人很震惊的以及疑惑的,因为似乎找到了一部分原因但我们还是没搞清楚为什么。

第三步 尝试修复(未弄清根本原因的情况下)

有了这个思路的提示,我们试图尝试修复。按照业务需求,我们不能取消ActivityIndicator的使用,因为给用户适当的提示这个确实很有必要。

我们试图去修改mask的实现,在老的里面我们使用了一个第三方的RN组件react-native-root-siblings来帮助我们在root同级插入一个兄弟元素显示我们的loading提示符号。

一般在发完请求请求结果未到达之前,我们就插入一个新的同级兄弟元素,请求完成后就删除掉它。当时怀疑因为这部分反复的修改页面的元素结构,就把new-destory的逻辑换成了new-update的逻辑,减少了元素的修改。update的时候只是去让ActivityIndicator不出现似乎被hide了。

第四步 测试bug是否还能重现

我们希望通过减少页面元素反复的删除创建,来fix这个bug,结果怎么样呢?
居然神奇的很难复现了,我们很开心,虽然还是没弄懂原因。
后面QA说在真机上还是遇到了几次,让我们更是费解,费解的是出现的概率确实变少了,但为啥还会出现?

第五步 分析bug产生的根本原因

这个时候我们需要了解bug产生的真正原因了。
我们重新回到这个bug的表现,为什么点击空白区域会触发TextInput的focus方法?我们尝试做了这样几件事情。

找出在会触发TextInput的focus的地方

除了在代码逻辑里面少量的通过绑定ref然后触发.focus方法(因为是少量出现,不符合我们这个bug一出现所有input都受影响的情景,快速排除不是这部分原因),我们发现在RN提供的TextInput组件里面也有很多地方会调用到focus方法。