写点什么

提升海量用户极致体验的 Hybrid 架构设计(原理篇)

  • 2020-02-21
  • 本文字数:4230 字

    阅读完需:约 14 分钟

提升海量用户极致体验的Hybrid架构设计(原理篇)

一、引言

随着 Web 技术和移动设备的快速发展,Hybrid 技术已经成为一种最主流最常见的方案。一套好的 Hybrid 架构方案能让 App 既能拥有极致的体验和性能,同时也能拥有 Web 技术灵活的开发模式、跨平台能力以及热更新机制,想想是不是都鸡冻不已…本系列文章是美图公司在这方面实践的一个总结,包含了原理解析、方案选型与实现、实践优化等方面。


大家可以到 github (https://github.com/xd-tayde/blog/blob/master/hybrid-1.md)上和作者进行讨论哈!

二、现有混合方案

Hybrid App,俗称混合应用,即混合了 Native 技术 与 Web 技术进行开发的移动应用。现在比较流行的混合方案主要有三种,主要是在 UI 渲染机制上的不同:


1.基于 WebView UI 的基础方案,市面上大部分主流 App 都有采用,例如微信 JS-SDK ,通过 JSBridge 完成 H5 与 Native 的双向通讯,从而赋予 H5 一定程度的原生能力。


2.基于 Native UI 的方案,例如 React-Native、Weex。在赋予 H5 原生 API 能力的基础上,进一步通过 JSBridge 将 js 解析成的虚拟节点树( Virtual DOM )传递到 Native 并使用原生渲染。


3.另外还有近期比较流行的小程序方案,也是通过更加定制化的 JSBridge,并使用双 WebView 双线程的模式隔离了 JS 逻辑与 UI 渲染,形成了特殊的开发模式,加强了 H5 与 Native 混合程度,提高了页面性能及开发体验。


以上的三种方案,其实同样都是基于 JSBridge 完成的通讯层,第二三种方案,其实可以看做是在方案一的基础上,继续通过不同的新技术进一步提高了应用的混合程度。因此,JSBridge 也是整个混合应用最关键的部分,例如我们在设置微信分享时用到的 JS-SDK,wx 对象便是我们最常见的 JSBridge:


三、方案选型

任何技术方案的选型,其实都应该基于使用场景和现有条件。基于公司现有情况的几点考虑,在方案一上进一步优化,更加适合我们的需求。


  • 需求 Web 技术 快速迭代、灵活开发的特点和线上热更新的机制。

  • 产品的核心能力是强大的拍照与底层图片处理能力,因此单纯的 H5 技术能做的事非常有限,不能满足需求,通过 Hybrid 技术来强化 H5 ,便是一种必需。

  • 公司业务上,并没有非常复杂的 UI 渲染需求,而且 App 中的一系列原生 UI 组件 已经非常成熟,因此我们并不强需类似 RN 这样的方案。


因此,如何既能利用 H5 强大的开发和迭代能力,又能赋予 H5 强大的底层能力和用户体验,同时能复用现有的成熟 Native 组件,便成为了我们最大的需求点 – 一套完整又强大的 Hybrid 技术架构方案。

四、Hybrid 技术原理

Hybrid App 的本质,其实是在原生的 App 中,使用 WebView 作为容器直接承载 Web 页面。因此,最核心的点就是 Native 端与 H5 端之间的双向通讯层,其实这里也可以理解为我们需要一套跨语言通讯方案,来完成 Native(Java/Objective-c/…) 与 JavaScript 的通讯。这个方案就是我们所说的 JSBridge,而实现的关键便是作为容器的 WebView,一切的原理都是基于 WebView 的机制。



4.1 JavaScript 通知 Native


基于 WebView 的机制和开放的 API , 实现这个功能有三种常见的方案:


  • API 注入,原理其实就是 Native 获取 JavaScript 环境上下文,并直接在上面挂载对象或者方法,使 js 可以直接调用,Android 与 IOS 分别拥有对应的挂载方式。

  • WebView 中的 prompt/console/alert 拦截,通常使用 prompt ,因为这个方法在前端中使用频率低,比较不会出现冲突;

  • WebView URL Scheme 跳转拦截;


第二三种机制的原理是类似的,都是通过对 WebView 信息冒泡传递的拦截,从而达到通讯的,接下来我们主要从 原理-定制协议-拦截协议-参数传递-回调机制 5 个方面详细阐述下第三种方案 – URL 拦截方案。

4.1.1 实现原理

在 WebView 中发出的网络请求,客户端都能进行监听和捕获

4.1.2 协议的定制

我们需要制定一套 URL Scheme 规则,通常我们的请求会带有对应的协议开头,例如常见的 https://xxx.com 或者 file://1.jpg ,代表着不同的含义。我们这里可以将协议类型的请求定制为:


xxcommand://xxxx?param1=1&param2=2


这里有几个需要注意点的是:


(1) xxcommand:// 只是一种规则,可以根据业务进行制定,使其具有含义,例如我们定义 xxcommand:// 为公司所有 App 系通用,为通用工具协议:


xxcommand://getProxy?h=1

而定义 xxapp:// 为每个 App 单独的业务协议。

xxapp://openCamera?h=2

不同的协议头代表着不同的含义,这样便能清楚知道每个协议的适用范围。


(2) 这里不要使用 location.href 发送,因为其自身机制有个问题是同时并发多次请求会被合并成为一次,导致协议被忽略,而并发协议其实是非常常见的功能。我们会使用创建 iframe 发送请求的方式。


(3) 通常考虑到安全性,需要在客户端中设置域名白名单或者限制,避免公司内部业务协议被第三方直接调用。

4.1.3 协议的拦截

客户端可以通过 API 对 WebView 发出的请求进行拦截:


  • IOS 上: shouldStartLoadWithRequest

  • Android: shouldOverrideUrlLoading


当解析到请求 URL 头为制定的协议时,便不发起对应的资源请求,而是解析参数,并进行相关功能或者方法的调用,完成协议功能的映射。

4.1.4 协议回调

由于协议的本质其实是发送请求,这属于一个异步的过程,因此我们便需要处理对应的回调机制。这里我们采用的方式是 JS 的事件系统,这里我们会用到 window.addEventListener 和 window.dispatchEvent 这两个基础 API;


  • 1.发送协议时,通过协议的唯一标识注册自定义事件,并将回调绑定到对应的事件上。

  • 2.客户端完成对应的功能后,调用 Bridge 的 dispatch API ,直接携带 data 触发该协议的自定义事件。

  • 通过事件的机制,会让开发更符合我们前端的习惯,例如当你需要监听客户端的通知时,同样只需要在通过 addEventListener 进行监听即可。

  • Tips: 这里有一点需要注意的是,应该避免事件的多次重复绑定,因此当唯一标识重置时,需要 removeEventListener 对应的事件。

4.1.5 参数传递方式

由于 WebView 对 URL 会有长度的限制,因此常规的通过 search 参数 进行传递的方式便具有一个问题,既 当需要传递的参数过长时,可能会导致被截断,例如传递 base64 或者传递大量数据时。


因此我们需要制定新的参数传递规则,我们使用的是函数调用的方式。这里的原理主要是基于:Native 可以直接调用 JS 方法并直接获取函数的返回值。


我们只需要对每条协议标记一个唯一标识,并把参数存入参数池中,到时客户端再通过该唯一标识从参数池中获取对应的参数即可。

4.2 Native 通知 Javascript

由于 Native 可以算作 H5 的宿主,因此拥有更大的权限,上面也提到了 Native 可以通过 WebView API 直接执行 Js 代码。这样的权限也就让这个方向的通讯变得十分的便捷。


  • IOS: stringByEvaluatingJavaScriptFromString

  • Android: loadUrl (4.4-)

  • Tips: 当系统低于 4.4 时,evaluateJavascript 是无法使用的,因此单纯的使用 loadUrl 无法获取 JS 返回值,这时我们需要使用前面提到的 prompt 的方法进行兼容,让 H5 端 通过 prompt 进行数据的发送,客户端进行拦截并获取数据。

  • Android: evaluateJavascript (4.4+)

  • 基于上面的原理,我们已经明白 JSBridge 最基础的原理,并且能实现 Native <=> H5 的双向通讯机制了。

4.3 JSBridge 的接入

接下来,我们来理下代码上需要的资源。实现这套方案,从上图可以看出,其实可以分为两个部分:


  • JS 部分(bridge): 在 JS 环境中注入 bridge 的实现代码,包含了协议的拼装/发送/参数池/回调池等一些基础功能。

  • Native 部分(SDK): 在客户端中 bridge 的功能映射代码,实现了 URL 拦截与解析/环境信息的注入/通用功能映射等功能。


我们这里的做法是,将这两部分一起封装成一个 Native SDK,由客户端统一引入。客户端在初始化一个 WebView 打开页面时,如果页面地址在白名单中,会直接在 HTML 的头部注入对应的 bridge.js。这样的做法有以下的好处:


  • 双方的代码统一维护,避免出现版本分裂的情况。有更新时,只要由客户端更新 SDK 即可,不会出现版本兼容的问题;

  • App 的接入十分方便,只需要按文档接入最新版本的 SDK ,即可直接运行整套 Hybrid 方案,便于在多个 App 中快速的落地;

  • H5 端无需关注,这样有利于将 bridge 开放给第三方页面使用。


这里有一点需要注意的是,协议的调用,一定是需要确保执行在 bridge.js 成功注入后。由于客户端的注入行为属于一个附加的异步行为,从 H5 方很难去捕捉准确的完成时机,因此这里需要通过客户端监听页面完成后,基于上面的事件回调机制通知 H5 端,页面中即可通过 window.addEventListener(‘bridgeReady’, e => {})进行初始化。

4.4 App 中 H5 的接入方式

将 H5 接入 App 中通常有两种方式:在线 H5 和内置包 H5。


(1) 在线 H5,这是最常见的一种方式。我们只需要将 H5 代码部署到服务器上,只要把对应的 URL 地址 给到客户端,用 WebView 打开该 URL,即可嵌入。该方式的好处在于:


  • 独立性强,有非常独立的开发/调试/更新/上线能力;

  • 资源放在服务器上,完全不会影响客户端的包体积;

  • 接入成本很低,完全的热更新机制。


但相对的,这种方式也有对应的缺点:


  • 完全的网络依赖,在离线的情况下无法打开页面;

  • 首屏加载速度依赖于网络,网络较慢时,首屏加载也较慢;


通常,这种方式更适用在一些比较轻量级的页面上,例如一些帮助页、提示页、使用攻略等页面。这些页面的特点是功能性不强,不太需要复杂的功能协议,且不需要离线使用。在一些第三方页面接入上,也会使用这种方式,例如我们的页面调用微信 JS-SDK 。


(2) 内置包 H5,这是一种本地化的嵌入方式,我们需要将代码进行打包后下发到客户端,并由客户端直接解压到本地储存中。通常我们运用在一些比较大和比较重要的模块上。其优点是:


  • 由于其本地化,首屏加载速度快,用户体验更为接近原生;

  • 可以不依赖网络,离线运行;


但同时,它的劣势也十分明显:


  • 开发流程/更新机制复杂化,需要客户端,甚至服务端的共同协作;

  • 会相应的增加 App 包体积;


这两种接入方式均有自己的优缺点,应该根据不同场景进行选择。

五、总结

本文主要解析了现在 Hybrid App 的发展现状和其基础原理,包含了


  • JavaScript 通知 Native

  • Native 通知 Javascript

  • JSBridge 的接入

  • H5 的接入


只有在了解了其最本质的实现原理后,才能对这套方案进行实现以及进一步的优化。接下来,我们将基于上面的理论,继续探讨如何把这套方案的真正代码实现以及方案优化方案,欢迎大家一起讨论!


作者介绍:郭晓东,美图前端工程师,一只有梦想、爱技术的前端程序猿。


本文转载自美图技术公众号。


原文链接:https://mp.weixin.qq.com/s/W6I0iF2oPSAJARxGVqtq6w


2020-02-21 22:512412

评论

发布
暂无评论
发现更多内容

如虎添翼!微软OneNote迎来新利器!

Jackpop

Vue组合式函数(一)

Augus

vue.js 11月月更

网络安全必学SQL注入

网络安全学海

网络安全 安全 信息安全 渗透测试 漏洞挖掘

工赋开发者社区 | SPL工业智能:发现时序数据的异常

工赋开发者社区

微服务先等等,我去刷个“虚拟背景”的副本

为自己带盐

虚拟背景 11月月更 trtc

产品负责人的轻度思考,6个小策略,面对迭代Sprint评审会

老彦

敏捷 回顾会 产品负责人

Mac上有那些你认为极其好用的app?

Jackpop

HNCTF--Misc部分题解

我是一个茶壶

11月月更 杂项 HNCTF

应用防火墙WAF架构分类

阿泽🧸

waf 11月月更

华为高清空间音频将登陆座舱,打造移动“车载大剧院”

最新动态

新一代 CI 即将到来!

CODING DevOps

ci 持续集成 jenkins

网易云信智码超清转码技术实践

网易云信

音视频开发

九科信息荣获《2022爱分析RPA厂商全景报告》RPA软件市场代表厂商

九科Ninetech

华为阅读“WebBrain搜索”和“知识图谱”在HDC2022首次亮相!

叶落便知秋

全新升级的鸿蒙开发套件,你想知道的都在这里

HarmonyOS开发者

HarmonyOS

华为发布鸿蒙开发套件 全面加速推进鸿蒙生态

科技汇

卷积模型分类图片

梦笔生花

Python 卷积网络 11月月更

【C语言】case 关键字

謓泽

11月月更

前行不缀 未来可期,鸿蒙生态发展迈入全新阶段

OpenHarmony开发者

OpenHarmony

SQL Sever 提供的数字类型

乔乔

数据库 11月月更 SQL sever

如何通俗易懂理解Python类和面向对象?

Jackpop

独有且优质!这些Mac软件绝了!

Jackpop

阿里进入“全面云原生深度用云”阶段 PaaS支出占用云总成本43%

阿里技术

云计算 云原生 云栖大会

docker 部署 apache 做反向代理

非晓为骁

Apache Docker 反向代理

概述DDoS分类

穿过生命散发芬芳

DDoS 11月月更

作为资深Mac用户,有哪些你相见恨晚的软件值得推荐?

Jackpop

使用 apache 给前后端服务做反向代理

非晓为骁

Apache 反向代理

阿里低代码引擎怎么样,好不好用?

优秀

低代码

NB的Github项目,看到最后一个我惊呆了!

艾小仙

Java GitHub

因热爱而分享!阿里云开发者社区 X InfoQ创作者支持计划发布

阿里技术

深扒:基于UEBA的数据使用安全防护

极盾科技

提升海量用户极致体验的Hybrid架构设计(原理篇)_行业深度_郭晓东_InfoQ精选文章