How to make webview faster (II)

作者 Zhe Wang 日期 2017-12-24
web
How to make webview faster (II)

在按照上篇文章的相关思路进行前端调优之后,其实一个webview的访问已经基本能满足要求。这篇文章我从App客户端层面分享一些可进一步优化的策略,由于我是负责ios部分,所以是以xcode为例。

在17年6月份曾经去北京参加GMTC,有一场分享来自腾讯手Q关于webview的加载优化,如今他们已经推出了一个完整的框架VasSonic我比较认同其中的一个观点,许多优化都可以通过引入中间层来寻求答案。其实换言之,客户端的优化并不是用xcode或者java重新实现一个性能更高的webview,而是在现有基础上谋求突破。

前提

我想客户端优化一个必不可少的前提是,你必须能够掌控你的webview请求,说的更直白一些,我们可以拦截webview请求。我们在这里所说的请求,说的不单纯是资源请求,还包括各类业务数据请求。

直接拦截

实现拦截,我们的目标是尽可能少的侵入h5层代码,如果要为请求拦截实现额外的Bridge,是我们所不希望看到的情况。

这一点,IOS比较纯粹,可以通过继承NSURLProtocol并重载相关方法做到请求拦截。但是,Android就没那么容易了,WebView虽然提供了shouldInterceptRequest方法,但对POST请求拦截存在很大问题(我们的业务数据请求都是通过POST),需要在h5层额外实现Bridge,因此最终放弃了直接拦截的方案。

虚拟域的一种实践

知乎上的一篇回答给了我灵感,淘宝旅行提出虚拟域的概念,旨在弱网络或无网络环境下,将线上URL解析指向本地,从而加载本地离线文件。因此,我们也对自己的工程进行了一次虚拟域的实践,在客户端本地架设一个简易server。

原有WebView加载方式


原有方式存在几个问题

  1. server端需要允许跨域请求
  2. 对业务数据的缓存只能在h5层进行,为了实现持久化存储,我们需要有专门的Bridge将待缓存数据从h5层搬移到RN/Xcode层,并将已缓存数据从RN/Xcode层搬到h5层。

虚拟域实践

进行改造后,上述两个问题可以得到解决。在做到请求拦截的同时,对h5代码的侵入性也是非常少的,基本只需要修改所有请求的host。当然,对业务数据请求进行拦截,包括请求header、请求body的获取再转发,是需要在本地server做的工作。

虚拟域并非目的

如果单纯为了解决上述两个问题,虚拟域的引入并没有对webview的加载优化起到什么实际的作用。

让我们先看一看,一次完整的webview加载,都经过了什么过程

可以看出,从webview实例化,到js的执行之前,这一段都是网络的闲置时段。因此在webview实例化的时候,我们另起一个线程,并行进行业务请求。在js执行时候的业务请求,直接去进程变量中拿取数据。当然,进程变量中所期望的那段数据可能仍在等待响应的状态,我们此时会进行小间隔的轮询,直到取到数据。

webview预加载及复用

在对webview加载进行时间统计的过程中,iphone 6s为例,正常电量模式下,webview实例化需要大概100ms~200ms,而在省电模式下,所花费的时间更多。因此,我们提出Webview Pool的概念,即一组已经初始化的webview,用于路由栈各层场景进行重复使用。

static NSMutableArray * preloadWebView;

@implementation MyWebViewPool

-(instancetype)init{
self = [super init];
preloadWebView = [NSMutableArray arrayWithCapacity:3];
MyWebView * webview0 = [[MyWebView alloc] init];
webview0.idx = 0;
MyWebView * webview1 = [[MyWebView alloc] init];
webview1.idx = 1;
MyWebView * webview2 = [[MyWebView alloc] init];
webview2.idx = 2;
[preloadWebView addObject:webview0];
[preloadWebView addObject:webview1];
[preloadWebView addObject:webview2];
return self;
}

Webview Pool中实例化的webview数量,可以根据具体业务需求进行增删。一般情况下,越是栈数深的场景,被使用到的频率越低,对于webview的加载速度要求也越低。

效果

按照上述依赖虚拟域实现网络闲置时段的利用webview预加载及复用两个方向进行优化,以邮件详情界面的打开为例,对比一下速度。

p.s.

以上是我们在客户端的优化实践,当然,webview的优化方案还有很多,并不是每种方案都适用自己,还是具体情况具体分析。