移动端H5容器建设体系

1,334 阅读12分钟

前言

目前移动端的开发体系中,经常会跟H5,也就是WebView打交道。如果是熟悉这块的同学,肯定有被老板/同事吐槽过“这个页面打开的速度也太慢了!”,或者“这一块怎么Android和IOS上表现还不一样的?”,这些可以说是我们的心病了。虽然我们充当缝纫工的角色一直在修修补补,但找个时间想想,我们干了些什么呢?未来又能干些什么呢?可能一下子也说不上来。

那么今天我们就要解决这一个问题。这篇文章将梳理出业内主流APP的H5容器建设体系,为我们更加清晰地指明H5容器建设的方向。如果你恰巧是H5容器负责人,那么你就有福了,升职加薪全靠它了。如果你还没有接触过H5容器,没关系,通过这篇文章你将知道一个全貌,之后总会用上的。

当然,我所列的仅作为一个参考,还有很多牛逼的能力我也是不知道的,目前还在持续学习中,但下面的能力在日常开发中已经足够我们去使用了。

根据我的调研与经验总结,一个成熟的H5容器,应该至少具备这四个方面的能力:双端异同、容器架构、性能体验、研发效能。相应的,容器建设也将围绕这四点展开。

双端异同

双端异同,其实就是指双端的一致性与非一致性。一致性很好理解,主要是有协议的一致性与UI的一致性。

协议一致性

  1. 开发过程中,Android、IOS、前端需要约定好scheme协议,从而保证路由跳转、唤端链路在两端APP上达到的效果都是一致的。
  2. 在前端需要调用Native接口能力时,JSBridge协议同样需要保持一致,避免前端区分系统去调接口的情况发生(if android do this else if ios do the other)。
  3. 拦截协议统一。哪些页面能打开,哪些页面不能打开,即页面的黑白名单,双端需要保持一致。同时,哪些页面的重定向需要拦截,甚至基于拦截重定向自己实现跳转,也需要保持一致。

UI一致性

UI一致性指的是双端H5容器所拥有的基础组件需要保持一致。比如容器的Loading、容器导航栏、容器异常态UI等。

非一致性

一般情况下,非一致性其实也都是关于UI的。

比如IOS系统的用户习惯在控件上左滑,用于显示“更多”、“操作”按钮,而Android系统的用户则习惯在控件上长按去显示出来,这样的交互可以在逻辑中将系统进行一个区分。

再比如很常见的适配工作,比如IPHONE 14浮动岛的适配,比如安卓状态栏与IOS状态栏安全区域的适配,以及不同小中大机型的屏幕适配,这些都是双端非一致性的地方,需要各端的开发独立去解决。

容器架构

演进阶段

容器架构是一个比较大的概念,但总体来说就是把H5容器的架构演进分成三个阶段:模块化>组件化>插件化

第一个阶段模块化,指的是将H5容器相关的代码单独抽成一个模块,隐藏内部的实现细节,只暴露业务侧需要调用的API接口(打开H5页面、新建一个WebView等)。

第二个阶段组件化,指的是H5模块可以脱离主工程,单独作为一个app运行。在多团队合作且主工程编译速度变慢的情况下,组件化能大大提高开发效率。

第三个阶段插件化,与组件化的区别在于,组件化虽然可以将H5模块作为一个app运行,但目标只是提高开发效率,最终还是要与主工程合为一个apk去进行发布。而插件化指的是H5模块可以单独作为一个apk,主工程apk先行发布,再远程下载H5模块apk,达到包瘦身与热修复的目的。

架构设计

再谈细节的架构设计,我们主要需要保证H5容器的通用性、易用性与扩展性

通用性指的是H5容器是否能打开任意一个H5页面,各类框架容器是否都已经被集成于自研的H5容器当中。比如用weex写的页面或者用普通H5写的页面,我们的H5容器都支持打开且不会有异常吗?

有时候通用性也指代码的通用性。比如新增的功能是否能复用之前的jsbridge能力,不同容器的WebViewClient是否能抽成一个WebViewClient进行统一管理等。

易用性指的是H5容器提供的接口API是否合理,业务方使用起来有没有什么难点。如何知道你的架构是否易用?问你的下游就知道了。

扩展性指的是当我们集成新的能力,或者需要开发一个新的容器相关需求,是否能迅速完成?历史包袱重不重,需不需要改造很多以前的代码造成回归范围难以把握?如果一个新的需求过来,你可以不改之前的一行代码,而只用增加一个逻辑分支,并且最终测试回归的范围不涉及到以前的场景,那就可以说明扩展性很强了。

具体可以参考网上很多大佬的例子,之前我也写过一篇《Android H5通用容器架构设计》,有兴趣也可以看一看。

监控体系

在容器架构中,监控体系是一个比较大的点。这里的监控体系指的是偏向于客户端侧的监控体系,跟H5的监控体系需要区分开。

两者的区别是客户端侧感知的范围是更宏观的,比如H5容器的跳转、初始化、销毁。但更加微观的部分,则由H5的监控体系去观测,例如资源异常监控、js异常监控、api请求监控等。可以说,客户端侧监控的是容器这一部分,而H5受生命周期的限制,监控的是容器内WebView的运行情况。

而且有些时候,是需要客户端的监控体系与H5的监控体系一起去配合完成监控的。拿页面的加载时长来举例,跳转H5容器的时间是页面加载的起始时间,这个时机H5监控体系是拿不到的,只有客户端才能拿到。而页面加载的精确的结束时间,客户端同样是无法感知到的,只能依靠H5监控体系去拿,因为客户端的onPageFinished生命周期其实是晚于页面加载好的时机的,onPageFinished还包括了很多资源的加载时间。所以这里就需要两者结合起来去看,才能计算出精确的H5页面加载时间。

性能体验

众所周知,H5动态性虽强,但性能体验一直是其短板,那客户端侧可以做哪些性能优化来提升这一方面的体验呢?基于下面这张图,介绍客户端可以做的优化点。

image.png

WebView预创建

刚进入H5页面时由于需要初始化WebView内核,用户等待时间会比进入其它页面明显感觉要久。我们可以在APP启动后的某个时机,预创建WebView到内存中,在打开H5页面时容器将从内存中直取已初始化好的WebView,节省启动过程中WebView初始化的时间。

这项技术是不感知业务形态的,所有H5页面都可以使用。具体可以参考Android WebView预渲染

资源缓存

加载一个H5页面过程中,需要通过网络去请求一个个资源,如html、css、js、图片等,占用的时长从几十ms到几千ms不等,是非常耗时的。因此可以提前将资源预置或者下载到客户端本地,在H5请求资源时进行拦截,若匹配到了本地资源,就直接返回,省去网络的空中时间。

通过配置和管理资源包,可以适用于核心的H5页面。这项技术在后面我也会专门出一篇文章来介绍。

接口预请求Prefetch

与请求资源一个道理,H5页面的渲染依赖接口请求数据。但网络请求的发起时间其实是有点延后的,在网络请求之前还需要经历“容器初始化”>“WebView初始化”>“dom下载/解析”等过程。如果在容器初始化前就能发起请求,做到前面的链路与网络请求并发进行,等真正需要网络数据的时候直接从内存里直取,不就能直接省去等待网络请求的时间了吗?

预请求框架其实是比较轻量级的,而且接口预请求特别适合用于H5页面,因为H5页面在发起网络请求之前的链路是比较长的,等到真正需要网络数据的时候,预请求大概率是已经拿到数据的,可以直接省去网络时间,所以可以适用于核心的H5页面。具体可以参考Android斩首行动——接口预请求

WebView预渲染

WebView预渲染其实就是在预创建的基础上,执行WebView#loadUrl(),将页面提前渲染完成,也就是在用户还没打算打开某个页面的时候,app后台已经在内存里把某个WebView直接加载好了。等用户需要打开对应页面的时候,需要做的工作只有创建容器并且把加载好的WebView放进去就好了,直观感受就是秒开。

但这项技术相对而言是比较重的,且对内存会有比较大的影响,在应用的时候需要对预渲染的WebView数量进行严格控制,主要用于非常重要的,用户点击概率与点击频率都非常高的页面,如大促会场等。

具体可以参考Android WebView预渲染

同层渲染

同层渲染即在H5 WebView中使用native组件,内嵌到H5的Dom树中,并且native需要提供给H5完整的操作组件的接口,并透传组件的状态与事件给H5。

这项技术比较适合用于H5比较难写,或者H5上体验效果不佳,或者Native已有现成组件需要直接使用Native组件的场景。比如直播,通常都是需要native借助三方sdk实现组件。比如视频,在H5上的效果可能不太好,也可能需要用同层渲染。

研发效能

关于研发效能,其实能做的东西有很多,每个项目组都会根据自己的痛点去想尽办法去提高效能,甚至有专门做一个平台去一站式规范开发流程的。所以很难归纳出比较通用的能力,这里只列3点最基本的要求,大家可以根据自己项目组的情况去搞点东西出来,也欢迎在评论区留言让我学习膜拜一番。

调试工具

前端同学开发时,需要能连通手机与开发工具,实时打断点调试或者看日志。Google官方提供chrome://inspect工具,或者借助二方/三方平台来实现。

抓包工具

在PC上实时显示网络抓包情况,将网络数据结构化呈现,常见的有WireShark、Charles等。

客户端debug包辅助工具

如果什么都要借助PC去抓包、去看日志,在某些紧急情况会显得很不方便。并且实际开发、测试过程中,很多同学是区分不出来遇到的问题是属于H5容器的问题,还是属于H5页面本身的问题,导致客户端同学经常会拿到H5的异常,或者H5的同学经常会拿到容器的异常,这里还是有比较大的人力成本在的。

那么我们可以考虑在H5容器中,加入debug辅助工具,用来查看当前页面的相关信息(比如页面Url、Cookie、接口请求状态、是否发生js异常、是否发生白屏、容器的生命周期等),帮助业务与测试快速定位问题。

其它

主流APP还会集成端智能的能力,预测用户行为轨迹,从而更加精准、更加提前地实现预渲染、预请求。

端智能的集成是比较繁杂的,而且并不是单独针对H5容器使用的,是一项通用能力,所以大家可以视能力与项目组情况选择性地进行投入。这一块我自己也还没有接触过,留待后续调研哈~

总结

这篇文章,围绕双端异同、容器架构、性能体验、研发效能四个点,介绍移动端H5容器建设体系的全貌。建议大家如果有时间的话,可以从业务中抽身出来,总结对比一下容器发展的现状,然后就能得出后面发展的规划了,对自己,对老板,就都有交代啦~