作者:道乐科技

引言

对于一个普通用户来说,打开一个WebView通常会经历以下几个阶段:

1、交互无反馈

2、到达新的页面,页面白屏

3、页面基本框架出现,但是没有数据;页面处于loading状态

4、出现所需的数据

那么从程序上观察,WebView启动过程大概分为以下几个阶段:

根据上图所示,主要的步骤如下:

初始化 webview -> 请求页面 -> 下载数据 -> 解析HTML -> 请求 js/css 资源 -> dom 渲染 -> 解析 JS 执行 -> JS 请求数据 -> 解析渲染 -> 下载渲染图片

对于首屏启动速度影响最大的就是网络请求,包括请求HTML、css、image等静态资源,于是我们上期推出了离线包集成方案,将H5需要的静态资源打包到客户端中,缩短了这些过程。

那么这期我们将通过分析加载webview的各个阶段,来讲解需要注意的优化以及安全点。

初始化

对于APP来说,WebView的第一步并不是建立连接,而是启动浏览器内核,只有当创建WebView实例的时候,才会创建WebView的基础框架。

我们通常统计的页面打开时间,基本上是以建立网络连接作为起点的。

WebView初始化

对于APP来说,WebView的第一步并不是建立连接,而是启动浏览器内核,只有当创建WebView实例的时候,才会创建WebView的基础框架。

我们通常统计的页面打开时间,基本上是以建立网络连接作为起点的,所以通过定义指标以及测试数据来分析下启动内核的耗时。

  • 首次初始化时间:客户端冷启动后,第一次打开WebView,从开始创建WebView到开始建立网络连接之间的时间。
  • 二次初始化时间:在打开过WebView后,退出WebView,再重新打开WebView,从开始创建WebView到开始建立网络连接之间的时间。
10次平均值首次初始化时间(ms)二次初始化时间(ms)
iOS(UIWebView)306.5676.43
iOS(WkWebView)763.26457.25
Android192.79142.53
相当于客户端需要先花费70~700ms的时间初始化WebView完成之后,才开始加载。对于用户而言,体验到的打开时间也相应的增加,这也是“为什么WebView总是很慢”的原因之一。

全局WebView

由于初始化过程发生在客户端原生代码中,而大部分方案也是通过前端和客户端协作完成,而全局WebView也是业界采用的比较通用的方案。

方法:

  • 在客户端刚启动时,就初始化一个全局的WebView待用,并隐藏;
  • 当用户访问了WebView时,直接使用这个WebView加载对应网页,并展示。

这种方法可以比较有效的减少WebView在App中的首次打开时间。当用户访问页面时,不需要初始化WebView的时间。当然这也带来了一些问题,包括:

  • 额外的内存消耗。
  • 页面间跳转需要清空上一个页面的痕迹,更容易内存泄露。

客户端代理数据请求

在WebView初始化的过程中,数据请求是可以与其并行进行,总体的页面加载时间会相应缩短,也就缩短总体的页面加载时间。

方法:

  • 在客户端初始化WebView的同时,直接由native开始网络请求数据;
  • 当页面初始化完成后,向native获取其代理请求的数据。 

还有其他各种优化的方式,不再一一列举,总结起来都是围绕两点:

  1. 在使用前预先初始化好WebView,从而减小耗时。
  2. 在初始化的同时,通过Native来完成一些网络请求等过程,使得WebView初始化不是完全的阻塞后续过程。

加载

        由于静态资源的离线化处理,那么HTML只需要进行展示数据的请求,而常用的方式有两种:

  1. 通过客户端将展示数据传给页面,通过webview加载展示,这样几乎不需要网络请求,webview只要渲染页面,执行js即可。但是需要本地 H5页面跟native进行通信。
  2. 通过H5的AJAX去获取接口数据。那么就要求webview能允许跨域访问,这个方式就会出现对应的跨域漏洞问题。

那么在我们允许webview进行跨域访问的前提下,我们来讲解下如何针对性的进行处理。

访问网络资源URL

加载过程中,需要确定需要访问的网络资源URL,即为初始化资源对象。在集成了离线化方案的前提条件下,这里的网络资源即为APP沙盒中的某资源路径。示例如下:

由于这个过程发生在native的代码中,所以我们需要关注的是程序的反调试以及反注入的安全危险。目前常用的方案是通过ptrace方式来检测进行是否正在被调试以保护我们的应用。

建立、加载网络请求

初始网络请求对象并且进行加载,示例如下:

对于WkWebView来说,本次加载请求中,需要设置访问路径accessUrl,保证访问的资源文件路径是指定的、认可的。这里除了可能存在的accessUrl机制需要注意外,其余的处理方向跟上一步骤的一样。

处理服务器数据回调

下面的图是以加载www.qiyi.com为例子,描述了在最后发送请求给服务器之后,整个webview的一个加载以及调用过程。其中有对应的一个重定向的过程。可以从图中看出,不管最后其中的过程如何,最后都会执行到decidePolicyForNavigationAction的响应方法中。而我们需要做的就是在这个方法里进行加载链接的一个拦截以及检测安全处理。比如说检测我们最后加载的url是否我们信任的,是否在我们的白名单中的,避免最后用户在这个过程中重定向了非法恶意的路径。

HTML与Native进行JS请求数据

简单来说就是h5通过Ajax发送网络请求。前面讲到,在以允许h5进行跨域的前提下,所以Ajax可针对”file://”域发送请求,从而获取到APP的一些沙盒信息或者用户信息。

针对这种情况,原生端则可以通过NSURLProtocol来监听整个APP的一个网络请求。直接拦截掉不合法的请求,避免恶意的攻击。示例如下:

关于优化、安全

通过本节内容,给大家稍微简单的介绍了一些的性能、体验和安全的问题处理。随着技术的发展,WebView的性能、体验和安全问题也在逐渐的改善,并且其在APP中的占比越来越重的同时,如何更好的提高WebView的性能以及考虑WebView的安全性,也是一个不可忽视的方向。我们也在致力解决各种问题,提高用户体验的方向上不断摸索前进。

0

道乐研究院