NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

提升海量用户极致体验的 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:511917

评论

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

快速上手AppUploader——下载和安装操作

雪奈椰子

23年国内最牛的Java面试八股文合集(全彩版),不接受反驳

做梦都在改BUG

Java java面试 Java八股文 Java面试题 Java面试八股文

最佳实践 | 使用WebSocket做个实时人脸活体比对服务

牵着蜗牛去散步

人工智能 腾讯 最佳实践 腾讯云智能 慧眼人脸核身

网易云信 Crash 异常治理实践 | 智企技术委员会技术专题系列

网易智企

系统设计 异常处理

如何使用Xcode打包导出IPA文件并进行iOS应用内测,无需支付苹果开发者账号费用?

雪奈椰子

ios打包

Windows2008与Windows2012下使用IIS服务搭建网站

百度开发者中心

windows IIS 云服务器

选对调度器,让你的设备“纵享丝滑”

鼎道智联

算法 cpu ESA

软件测试/测试开发 | 数据持久化技术(Java)

测试人

软件测试 测试发开

瓴羊Quick BI是一款成熟产品,数据可视化功能优势明显!

夏日星河

云服务器建站教程:云服务器部署SSL证书-Nginx

百度开发者中心

centos 云服务器

Linux系统搭建FTP服务

百度开发者中心

ftp服务

关于微服务系统中数据一致性的总结

做梦都在改BUG

Java 微服务 数据一致性

如何让SpringBoot项目启动时执行特定代码

做梦都在改BUG

Java Spring Boot

直播预约|Search for Future,阿里云 × Elastic 中国用户峰会 2023

阿里云大数据AI技术

大数据 阿里云 搜索

我的天,你还不会搭建ChatGPT微应用吗?| 社区征文

三掌柜

人工智能 openai ChatGPT

AppUploader教程:如何注册账号并激活AppUploader

雪奈椰子

DAPP/伪DAPP区块链智能合约系统开发(成熟技术)

I8O28578624

黑盒测试方法—等价类划分法

测吧(北京)科技有限公司

测试

预售登上计算机新书热卖榜TOP1,开年重磅,助力Java程序员飙升核心技能

图灵教育

Spring boot starter test java 后端、 程序员 java

京东二面,Redis为什么这么快?

做梦都在改BUG

Java 数据库 redis 缓存 面试

数据库大牛推荐的《MySQL》书籍,值得反复阅读

NineData

MySQL 程序员 书籍推荐 MySQL 高可用 学习MySQL

快速打包、发布和管理应用——AppUploader工具介绍

雪奈椰子

阿里内网「MySQL面试小册」,简直太香了!

做梦都在改BUG

Java MySQL 数据库 面试

2022中国低代码全景产业研究报告

人称T客

云服务器建站教程:云服务器部署SSL证书-Apache

百度开发者中心

centos 云服务器 LAMP

AppUploader教程:如何使用该工具制作Apple证书

雪奈椰子

ios打包

宝刀未老!VB语言迎来春天,低代码绝地逢生,程序员能淡定吗?

这我可不懂

低代码 低代码平台 JNPF Visual

网易云信 Crash 异常治理实践 | 智企技术委员会技术专题系列

网易云信

系统设计 异常处理

GitHub破千Star!Java多线程编程实战指南:核心篇+设计模式篇

做梦都在改BUG

Java 并发编程 多线程

Gartner首次针对中国市场发布产业数字化白皮书,联合卡奥斯共探区域经济发展最优解

Openlab_cosmoplat

数字化 产业数字化 白皮书 开源社区 Gartner

云服务器建站教程:Centos-7.2部署LNMP环境

百度开发者中心

云服务器,

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