如何设计一个好的WebView容器

Posted by wbq on September 6, 2021

前言

众所周知,iOS的网页组件很封闭,基本就是基于WKWebview修修改改。看起来能做的不多,但是一个好的webview容器,其实能做的事情还有很多。今天想聊一下,一个好的webview的容器,除了自己本身的功能,还需要哪些设计。

1.jsbridge的设计

wk很容易就可以使用jsbridge,只要在configuration.userContentController注入调用名

- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;

在js中附上刚面的name就可以调用了,非常方便

1
window.webkit.messageHandlers.name.postMessage()

同时也可以在想要的时间点(一般在初始过程)注入JS。


[userContentController addUserScript:[[WKUserScript alloc] initWithSource:script
																		injectionTime:WKUserScriptInjectionTimeAtDocumentStart
																	 forMainFrameOnly:YES]];

健全的容器,需要健全的bridge方法,比如容器的版本,基础的设备信息等等。业务功能比如照片选择器、图片浏览器、原生扫码页、蓝牙等等,都可以按需加入。当然光提供bridge,几个还好,一旦多起来,他们就需要体系,接收方法需要统一入口,交由容器解析,有一套健全的派发逻辑,因为native的方法代码可能散落在工程各处。返回结果需要统一出口,由容器统一格式返回。

而在js端调用的过程中需要规范调用的格式,入参的规则,成功和失败的回调规则。当native执行完毕之后,需要告知js侧结果。

image-20210903110547976.png

2.同层渲染

让网页拥有原生组件的能力,这是近两年比较火的同层渲染技术。

市面上的实现原理也已经比较成熟,具体实现可以看微信这篇小程序同层渲染原理剖析写的非常详细。

github上也有相关的源码级别实现。iOS的做法来说相对来说“trick”一些,而android在实现上会更加复杂一点。

3.离线加载

故名思议通过加载本地的资源进行网页的渲染,达到网页秒开的效果。

在这其中,资源的动态的下发是比较重要的一环,下发的时间点,如何正确的命中用户都是需要做的课题。后续数据的追溯,命中情况等都需要监控。

当然,资源的管理是一方面,如果正确识别需要加载的URL绕过网络去加载本地的资源的这个过程同样需要精细化设计。WKWebView的请求拦截,网上基本说烂了,这篇文章基本是结贴WKWebView 请求拦截探索与实践。市面上思路都差不多,”WKWebView不支持http、https拦截”、”Body丢失”、”Cookie同步”这些问题只要花时间都是有解的。

补充:关于body丢失的问题,不管是用NSURLProtocol或者WKURLSchemeHandler,基本都是需要js端配合hook XMLHTTPRequest,只需在容器启动从native注入hook的js,对前端同学同样也是透明的,没有负担。

4.性能稳定监控

基本的性能监控不能少,统计网页从打开到显示的时间,网页加载完毕时候统计是否是白屏等等。

也可以通过一些网页的属性传给网页进行统计比如window.performance

补充:白屏的几种判别方法:1.截图像素点的判断。2.遍历dom节点查看是否有正常子节点。

5.预热

今日头条的详情页部分是通过WKWebView进行渲染的,好的用户体验的一个很重要的点就是wk的预热和复用,详见参考中的链接。

6.其他

大的块暂时能想到的就这么多,剩下的定制化功能其实还有很多,开发者可以不断地往上垒,治理好bridge是关键,比如容器可以支持查看js日志,并且在线调试,增加一些对navibar,navibaritem,横屏,手势等进行设置的功能,又比如将网页一些耗时任务交给native处理,在体验上也会有不错的效果。

总结

相比于flutter,我其实更崇尚基于native + h5的这种hybrid开发,随着h5的体验越来越好,其实这种开发方式已经是目前主流的开发模式了,不管是从效率、易用、容错等方面都是一个相当不错的选择。

参考

今日头条品质优化 - 图文详情页秒开实践

小程序同层渲染原理剖析

WKWebView 请求拦截探索与实践

WBWebViewConsole