hybrid h5

hybrid 翻译为杂交, hyrid h5 是指将web前端页面嵌入到原生APP( iOS和Android )中的运行的方案。
相对于原生开发,web前端的开发发展时间更长、从业人员更多、生态更为繁荣,而且开发效率也更高。
但web并不能直接调用原生API,而且运行内存、调度也差与原生,流畅性就显得不足。
基于以上原因,协调开发资源,将一些展示性、交互不多的页面让web开发,嵌入原生Webview中运行,就可以大大提高APP开发效率,利用团队开发资源。

h5调用原生方法

参考 (https://github.com/marcuswestin/WebViewJavascriptBridge)

  1. 直接注入调用
    iOS能访问Webview下全局对象window,所以可以将js方法挂载到window上,然后iOS调用;
    安卓的话可以注入方法到window上,然后js调用这原生方法。
  2. 协议监听
    原生API能拦截Webview的网络请求,url根据协议传参,原生解析后执行,将结果挂载到window上。
    js的url实现方法:
    2.1 window.location.href
    2.2 利用页面中嵌套的iframe的url(将iframe的长宽都设为很小或者0,取到数据后再移除这个iframe)建议使用②iframe的方式,因为如果我们连续多次修改window.location.href的值,在Native层只能接收到最后一次请求,前面的请求都会被忽略掉。
  3. 引入JsBridge(安卓)和 WebViewJavascriptBridge(iOS)库的方案
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // 安卓运行
    // 如果WebViewJavascriptBridge已挂载,直接执行,否则,等待WebViewJavascriptBridgeReady时间触发,即原生方法已挂载后执行
    if (window.WebViewJavascriptBridge) {
    //do your work here
    } else {
    document.addEventListener(
    'WebViewJavascriptBridgeReady'
    , function() {
    //do your work here
    },
    false
    );
    }

    // iOS运行
    function setupWebViewJavascriptBridge(callback) {
    if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
    if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
    window.WVJBCallbacks = [callback];
    var WVJBIframe = document.createElement('iframe');
    WVJBIframe.style.display = 'none';
    WVJBIframe.src = 'https://__bridge_loaded__';
    document.documentElement.appendChild(WVJBIframe);
    setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
    }

此次项目,我们直接进行的注入调用。
h5中涉及到摄像头拍照的功能,由原生提供,注入到h5中,挂载到window.api上,js则可以直接调用方法。

1
window.api.camera(params, function(){})    // 调用原生注入的API,参数不可缺少,传递params参数以及回调函数

html中引入一个固定名称的js文件供安卓注入,比如 android.js, 兼容安卓5,文件不能为空,所以可以声明一个无关紧要的变量或者console。

兼容遇到的问题

  1. 安卓5下需要对Promise reject进行处理,否在抛错
  2. es6 spread语法, …obj, 低版本下需要确定obj为Object,如果为’’,会抛错
  3. iOS调用js方法时,内部不能有Promise,否则会卡死,不执行回调
  4. 用iframe时,iOS会需要src同源,否则会解析失败
  5. iOS input输入框,需要父元素position不是static,或者input{transform:translateZ(0)}