在使用陆金所Android版本的App时,进入任何理财产品详情页,都显示为空白,无法进行查阅与购买。

问题截图


情景再现

系统版本

小米系统是升级后的最新版
Webkit内核版本:54.0.2840.85

发现截图中无法显示产品详情的问题后,我联系了陆金所的人工在线客服,在描述问题并提供截图后,客服告知需要1到2个工作日给出反馈。实际上并没有那么久,我是早上反馈的问题,下午临近下班时就收到了客服的回复电话。

客服应该是从开发那里得到了反馈邮件,在这里表扬一下陆金所响应问题的速度。无法显示的原因在于小米系统里使用的WebView内核版本是53或者54,这两个版本存在bug,解决办法也很“简单”,只要把它升级成55就可以了。这里的“简单”为什么打上了引号呢?因为升级WebView需要手机上装有GooglePlay,而由于众所周知的原因,国内的Android手机系统里,安装GooglePlay的少之又少。不过什么也难不住广大的网民朋友对墙外世界的向往,内事不决问百度,自然可以找到安装的途径。


解决途径

先安装Google框架,再安装GooglePlay后,在GooglePlay中搜索WebView进行升级安装,再打开陆金所——duang!问题迎刃而解了。


问题起因探究

在百度上搜不出任何国内开发者对这个问题的描述!按说但凡是使用了小米手机,只要升级到了最新版本,在打开WebView时都有很大可能遭遇这个问题,为什么内网上搜不到,我也很费解。

而在Google上,很容易就找到下面这篇由Chromium官方发布的文档:WebView FAQ for Symantec Certificate Transparency Issue

我在这里依个人理解简单描述一下,建议各位直接阅读原文,会认识得更加全面。

根本原因

从WebView的53版本开始,它要求所有被Symantec(赛门铁克)签署的证书,必须执行Chrome证书政策。但是,Chrome自己在进行验证时,竟然出错了!!!在加载具有Symantec证书的页面时,会导致onReceivedSslError()的回调,页面显示一片空白。

这算不算弄巧成拙?

影响范围

自Android L版本开始,WebView版本53和54会受到影响,55开始恢复正常。需要注意的是,问题并非是立刻显现的,而会在WebView的build date十周之后,才暴露出来。Build版本与过期时间如下表所示,这也就解释了为什么在我刚升级Android系统时并没有发生这个问题,而是在上周使用陆金所App时才显露出来。

Build ID Expiration Date
54.0.2840.68 12/27/2016
54.0.2840.85 1/7/2017

现身说法

为了验证上文的情况,我在代码中使用getPackageManager().getPackageInfo("com.google.android.webview", 0).versionCode察看小米手机的WebView版本号,果然是54.0.2840.85,不幸中招。

在通过GooglePlay安装最新的55.0.2883.91版本后,再打开陆金所App,一切正常了。

Q & A

Q:Android N系统也会遇到这个问题吗?怎么解决?

A:自L开始的系统都会遇到,而N系统由于不是使用单独的WebView,而是使用由Chrome提供的WebView,因此只要升级Chrome就可以。(在Chrome的属性里可以看到Webview版本)

Q:用户可以通过修改系统时间为未过期的时间,来避免这个问题吗?

A:笔者亲测可以,但是不建议这么做,有可能导致更多潜在的问题。

Q:可否通过UserAgent嗅探来解决这个问题?

A:验证失败发生在连接TLS层时,这时还没有发送UserAgent信息,意味着页面挂掉时候是还不知道UA的。如果一定要在TLS层获取UA也不是没有办法,但这么做过于复杂,并且不安全。

Q:开发者怎样修复这个问题呢?

A:唯一的修复办法是提示用户更新WebView,当发生问题时,WebView会发出一个onReceivedSslError()回调,但是回调里并没有足以说明问题的提示信息。并且通过这个回调来回避问题(比如停止使用证书)会导致更多安全隐患,强烈不建议这么做。


一些思考

整个问题的描述与解释看下来,还真不是陆金所团队的锅——好久没见寸志了,如果当面问他这个事,他一定摆着手说:这个锅我不背!要怪就怪Android碎片化太严重,尤其是国内市场,各大厂商把原生系统做做美化,改头换面,再预装一大堆垃圾软件,就摇身一变成了自己的东西。而关键特性又更新不及时,就导致了上文发生的问题。

Android系统的开放特性是一把双刃剑,就看我们怎么使用它。


====Ending====