记六一儿童节的一次问题排查

最近接手了离职同事的一个支付类项目,对于客户端来说,主要的工作在两部分:

集成其他项目组提供的framework静态库,与服务器端联调,跑通业务流程。

实现与后台H5页面的交互。

因为同事离职的时间点正好处在项目开始初期,集成静态库之后编译报错,尚未开始后续联调工作,所以我接手之后先着手解决了所有的报错问题,主要涉及到我们应用的工程代码与静态库中代码存在大量dulplicate symbols,后续与服务器端联调的时候发现了一个奇葩问题,也是今天这片文章介绍的重点。

问题描述

基于公司业务原因,我们去除掉一些内部的敏感信息,抽象出业务流程中各个参与角色如下:

业务流程上,我们作为调用方集成A-SDK,A-SDK中又集成了B-SDK,各自SDK对应各自的后台Server端,其中主体的支付流程是在B-SDK与B-Server端完成,通过回调的方法返回给A-SDK,A-SDK再通过回调返回状态到我们的客户端。

今天的问题场景发生在B-SDK中,使用B-SDK中自定义的WebView加载H5页面,页面本身是B-Server的同事开发的,页面的样式很简单,包含两处input,让用户输入手机号以及短信验证码,但是无论我们如何点击,都无法唤起键盘,这就很尴尬了。。。

问题推测

我们现在跳出来具体的场景,针对一个H5页面的输入框,点击之后无法唤起键盘,可能的原因有哪些呢?

根据以往的经验,我们可以推测以下几个方向:

输入框绑定了JS方法,点击之后页面发起了Native请求,调用客户端方法实现,客户端本地代码并没有实现。

键盘是安全键盘,没有发出对应的请求。

键盘是系统键盘,但是在模拟器上有Bug。

键盘是系统键盘,但是真机设备上有的不支持,是否不同的iOS系统修改了webView对应API支持。

键盘是H5页面实现的,与客户端无关,单纯的JS页面问题。

排查过程

首先我自己在本机运行我们的工程代码,好不容易走到了对应的H5页面(这里严重吐槽一些我们的测试环境,简直不能更烂,很多东西还是手动配置,各方服务器不定时的装版本重启),在模拟器上和真机设备上都复现了问题,那么排除了上述原因3。

后续接到了测试同事反馈,测试机上也出现了同样的问题。同时我们也联系A-SDK,B-SDK的同事帮忙测试,都反馈点击后正常唤起系统的数字键盘,使用的设备包括iPhone7P(iOS10),iPhoneX(iOS11.3),我自己的真机设备是iPhone6SP(iOS11.2.5),这样综合来看,排除原因4。

因为B-SDK之前已经提供给外部应用比较长的时间,生产环境上运行稳定,进一步了解到页面唤起的应该是系统自带的数字键盘或者用户安装的第三方公司键盘,所以排除原因1、2、5。

那么问题来了,上面的原因都不是,还会有什么其他原因呢?

我自己在网上搜索了多个关于页面input唤起键盘,大部分都是想要实现用户无需点击页面自动唤起键盘,如果是正常的点击唤起键盘,应该是不需要做任何手动的代码处理的。之后我重新对比我们应用与A-SDK、B-SDK的运行结果,这才发现了关键的差异:

在我们工程运行的控制台打印出了UIWebView中代理方法的日志,而其他的SDK运行demo时并没有出现。

因为本质上使用的都是B-SDK中自带的WebView,所以我去申请查看了B-SDK的打包工程。

根据我们控制台显示的结果,接收到了H5页面发起的Native请求,而B-SDK的代码中的确有打印日志的代码,但是对应请求的处理都被注释了,具体原因无法追溯了,因为上一任开发人员离职,也没有留下任何的文档说明,但是可以肯定的是,这些处理是我们集成的另一公共处理构件,暂且称为WebViewKit吧,这个模块主要是为了支持内部应用加载H5页面时,为页面调用Native端的能力提供支持,比如OCR、人脸识别、手势密码验证、指纹验证等等操作。

问题到这一步基本确定了方向,在我们的应用中点击输入框,发起了Native请求但是没有得到相应所以表现为没有唤起键盘,而正常的点击没有走发起Native请求,直接唤起系统键盘。所以下一步我们要做的就是调试JS页面代码。

网上有很多关于使用Safari调试客户端H5页面的教程,这里我就不详细展开了,简单来说就是客户端连上Mac电脑,然后打开Mac电脑上Safari浏览器的高级选项,勾选相关设置后操作App进入对应JS页面,点击Safari浏览器-开发选项中对应的页面URL,此时手机上页面会闪烁蓝色,Safari打开浏览器查看JS源代码,根据页面上的文字内容找到对应的JS方法,打断点调试。

页面引用了超过10个JS文件,根据我们的初步排查,找到了发送Native的方法请求,但是再往前的判断分支我们找不到了,无奈之下求助项目经理,请B-Server对应的开发人员过来帮忙看看,这位开发人员一开始总是强调他的代码没问题,态度也不好,但是鉴于我们为了排查问题,所以一直耐心和他沟通,最后跟他强调了我们应用和SDK的调用结果不一致,所以去排查JS页面对于应用渠道的判断,最终定位了问题原因。

定位原因

根本原因:B-server的页面先做了应用渠道的判断,如果是内部应用则走Native请求唤起安全键盘,如果是外部应用则不做处理,直接根据input属性唤起系统键盘。

我们的应用之所以有问题,是因为上送的UA中包含了对应的字符串,触发了页面的判断条件,走了行内渠道,但是因为B-SDK中注释了所有Native请求的处理,所以没有反应。

为什么B-SDK中默认走外部应用的流程呢,是因为业务上B-SDK这一套东西,一直以来都是提供给外部应用做的,从来没有开发过行内版本。所以我们这一次的项目其实是使用了一个不对口的SDK来上线流程。

问题修改

知道了问题原因,解决方案就好办了。最优的方案当然是B-Server页面去修改对应的JS方法,对于内部应用的这部分流程特殊判断处理。但是由于某些内部原因,加上项目投产时间等现实问题,这个方案无法实现,问题就变成了,如何在适应当前B-Server不做修改的情况下,保证我们上送UA中不包含标识字符串。

方案1:由A-SDK在提交对应的请求之前,对UA字符串做判断,如果包含则使用“”代替,流程走完不管成功还是失败,或者中途停止,都通过统一的回调方法回到我们的应用,这里再对UA字符串做判断,如果没有包含对应标识字符串,则拼接更新字符串。

方案2:由调用方修改,修改内容与方案1相同,只是代码写在调用方工程里。

方案虽然确定了,但是我们与A-SDK的开发人员产生了分歧,对方认为应该我们修改,他们作为中间渠道不应该做这个工作,而我们认为应该他们统一修改,这样保证了SDK的完整和独立性,避免将额外的操作加入到调用方,产生代码污染,以后再想要接入其他的内部应用,就不需要调用方做额外的修改了。

但是理想和现实真的有差距,最后我们僵持不下,只能去找A项目的架构师做仲裁,阐述了我们的意见之后,对方不出意外的选择我们修改。除了上述原因之外,其实还有更重要的是对方已经对接了外部应用,还有两天上线,他们不愿意去承担这样的风险。

思考和小结

这个问题查了整整一天,虽然比较累,但是也收获了一些感受和思考。

扩展技能树

我们平时的开发工作中,如果有机会,尽可能的多去了解一些相关的知识和方法。比如这一次排查问题,如果我们对JS页面的调试一无所知,那就无法获取到B-Server的调用逻辑,也就没有底气证明对方的Native请求调用,这种能力有时候不仅仅是自己的技能树扩展,更有可能对项目的进度产生至关重要的影响,因为在多方参与的项目中,很多的配合部门开发人员都有先入为主的偏见,因为大家平时都比较忙,而排查问题本身有可能耗费比较长的时间。大家都是做技术的,没有点实打实的证据,很难让对方顺利的配合你排查。所以不管是网络相关的HTTPS、证书验证,还是服务器端相关的JAVA编程,都尽可能的去扩展和学习。

学会借力

在遇到问题的时候,如果经过了自己的一番研究还是没有头绪,那我们应该适当的去借助其他的资源解决问题。如果这一次我们没有集中B-Server的开发人员,那么很多页面的JS调用逻辑就只能靠猜测了。在这个过程中,技术上我们可以学习其他的同事是如何去分析和解决问题,也可以学习不同的方向的开发人员看待问题的角度差异。其他的方面,我们也可以的培养和锻炼自己的沟通协调能力,学习在一个或者多个开发团队参与的项目中,如何推进项目、把控进度去保证正常的交付。

方案评审

一般的公司内部,技术方案的评审工作都是由架构师或者技术负责人去完成,目的是为了保证方案的正确性。我们这边也一样,是由项目的牵头应用的架构师完成。这一次的排查给我的感觉更明显,评审的结果往往不是由技术主导决定,而是业务上的的问题影响更多,比如距离投产上线时间太近了,修改的话风险太大,即便只是一个微小的字符串替换操作,对业务的影响几乎可以忽略。再比如为了某些考核或者KPI,从部门领导的角度又会有更多的考虑,这些就已经完全脱离了技术的评审要素了。这也提醒我在以后的工作中,看待一个项目或者技术方案的实施,可能是多方因素综合影响的结果,而不仅仅是技术实现上的差别了。

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20180602G17RA700?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券