Hybrid基本原理

本文原创:wangtiegangjavascript

背景介绍

Hybrid App,俗称混合应用,即混合了 Native技术 与 Web技术 进行开发的移动应用。兼具" Native App良好用户交互体验的优点 "和" Web App跨平台开发的优点 "。html

Hybrid APP底层依赖于Native提供的容器(UIWebview),上层使用Html&Css&JS作业务开发,底层透明化、上层多多样化,这种场景很是有利于前端介入,很是适合业务快速迭代。前端

相关方案

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

  1. 基于 WebView UI 的基础方案,经过JSBridge完成H5和Native的通讯,赋予H5必定的端能力。是一种基于WebView UI的解决方案。
  2. 基于 Native UI 的方案,例如 React-Native、Weex,在赋予 H5 原生API能力的基础上,进一步经过JSbridge将js解析为虚拟DOM传递到Native,并使用原生进行渲染。

架构介绍

经过JSBridge,H5页面能够调用Native的api,Native也可调用H5页面的方法或者通知H5页面回调,从而实现双向通讯,以下图 android

frame.png

技术原理

JavaScript 通知 Native

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

  1. API注入,原理其实就是 Native 获取 JavaScript环境上下文,并直接在上面挂载对象或者方法,使 js 能够直接调用,Android 与 IOS 分别拥有对应的挂载方式。具体方法以下:
class JsObject {
   @JavascriptInterface
   public String toString() { return "injectedObject"; }
}
webview.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new JsObject(), "injectedObject");
webView.loadData("", "text/html", null);
webView.loadUrl("javascript:alert(injectedObject.toString())");
复制代码

可是此方法使用须要注意:json

  • 在Android <=4.1.2 (API 16),WebView使用WebKit浏览器引擎,并未正确限制addJavascriptInterface的使用方法,在应用权限范围内,攻击者能够经过Java反射机制实现任意命令执行。
  • 在Android >=4.2 (API 17),WebView使用Chromium浏览器引擎,而且限制了Javascript对Java对象方法的调用权限,只有声明了@JavascriptInterace注解的方法才能被Web页面调用。
  1. WebView 中的 prompt/console/alert 拦截,一般使用 prompt,由于这个方法在前端中使用频率低,比较不会出现冲突;api

  2. WebView URL Scheme 跳转拦截;浏览器

第二三种机制的原理是相似的,都是经过对 WebView 信息冒泡传递的拦截,从而达到通信的,目前多使用后两种方法。缓存

实现过程以下:

定制协议

经过特定的参数转换方法,将传入的数据,方法名一块儿,拼接成一个url scheme,如

// 基本有用信息就是后面的callbackId,handlerName与data
API_Name:callbackId/handlerName?param0=xxx&param1=yyy
复制代码

经过上面的定义来对应Native层不一样的方法,并传递参数

消息发送

  1. 这里不要使用 location.href 发送,由于其自身机制有个问题是同时并发屡次请求会被合并成为一次,致使协议被忽略,而并发协议实际上是很是常见的功能。

咱们会使用建立 iframe 发送请求的方式。如

//建立隐藏iframe过程
var messagingIframe = document.createElement('iframe');
messagingIframe.style.display = 'none';
document.documentElement.appendChild(messagingIframe);

//触发scheme
messagingIframe.src = uri;  
复制代码
  1. 经过调用 onJsAlert(),onJsConfirm(),onJsPrompt(),方法回调拦截对话框消息
var data = {
    action:'xxxx',
    params:'xxxx',
    callback:'xxxx',
};
var jsonData = JSON.stringify([data]);
//发起弹框
window.prompt(jsonData);
复制代码

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

消息的拦截

对应上面消息的发送,消息的拦截方法以下:

  1. 客户端能够经过 API 对 WebView 发出的请求进行拦截:

    IOS上: shouldStartLoadWithRequest

    Android: shouldOverrideUrlLoading

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

  1. 以onJsPrompt为例,客户端能够经过 API 对 WebView 发出的请求进行拦截:

    IOS上: runJavaScriptTextInputPanelWithPrompt

    Android: WebChromeClient.onJsPrompt

    处理方式同上

参数传递

因为 WebView 对 URL 会有长度的限制,所以常规的经过 scheme参数 进行传递的方式便具备一个问题,即当须要传递的参数过长时,可能会致使被截断,例如传递base64或者传递大量数据时。因为 Native 能够直接调用 JS 方法并直接获取函数的返回值,所以咱们只须要对每条协议标记一个惟一标识,并把参数存入参数池中,到时客户端再经过该惟一标识从参数池中获取对应的参数便可。

协议回调

当消息发送到Native 层后,咱们便须要处理对应的回调,一样须要的处理过程:

  1. js 向业务层发送消息,并经过 window.addEventListener 注册惟一的自定义事件,并绑定到对应的事件上
  2. Native 层收到后执行相应的业务方法
  3. Native 层执行完相应的业务,调用Bridge的dispatch 方法,发送到js层
  4. js 层获取传回的数据,经过 window.dispatchEvent 触发相应的自定义事件,并执行对应的回调

Native 通知 JavaScript

因为 Native 能够算做 H5 的宿主,所以拥有更大的权限,上面也提到了 Native 能够经过 WebView API直接执行 Js 代码。

// IOS
webview.stringByEvaluatingJavaScriptFromString("alert('NativeCall')")

// Android 4.4-
webView.loadUrl("javascript:JSBridge.trigger('NativeCall')")

// Android 4.4+
mWebView.evaluateJavascript("javascript:JSBridge.trigger('NativeCall')", 	 new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String value) {
        //此处为 js 返回的结果
    }
});
复制代码

android系统在低于4.4时,evaluateJavascript 是没法使用的,所以单纯的使用 loadUrl 没法获取 JS 返回值,这时咱们须要使用前面提到的 prompt 的方法进行兼容,让 H5端 经过 prompt 进行数据的发送,客户端进行拦截并获取相应数据

离线资源

在线获取h5资源总会遇到网络问题,对于一些不会常常改变的资源放到本地缓存,能够提升访问速度和稳定性。

一般来讲,H5资源分为两种,常常更新的业务代码不常常更新的框架、库代码和公用组件代码,为了实现离线资源的共享,在H5打包时能够采用分包的策略,将公用部分单独打包,在本地也是单独存放

为了实现同一资源的线上和离线访问, Native 层须要对 H5 请求的资源进行判断,究竟是从线上获取仍是本地获取,这里咱们暂时称之为 LocalUrlRouter。

接下来就是如何获取离线资源了,咱们上面提到了 LocalUrlRouter,它负责线上资源到本地资源映射,咱们借鉴已有的映射规则:H5开发完成后会扫描H5项目而后生成一份线上资源和本地资源路径的映射表(source-router.json)。每次请求资源时,LocalUrlRouter 会检查映射表,若是本地有离线资源,则会返回本地资源,不然经过http请求获取线上资源。

还能够完善的地方资源包的更新,映射表对资源的缓存也能够动态的增长等

相关文章
相关标签/搜索