WebViewJavaScriptBridge 使用

379 阅读2分钟

一个做iOS的朋友找到我说,想要做到iOS原生和的webview的H5交互,我向他推荐了WebViewJavaScriptBridge。他说H5相关的他不会,让我给他写个例子。我就简单写了一个demo,记录一下。

原理什么的就不说了,先看怎么用,下面就直接上代码吧:

iOS 原生处理

// 引入
pod "WebViewJavascriptBridge"

//webview 注入 bridge
self.bridge = [WebViewJavascriptBridge bridgeForWebView:webView];
[self.bridge setWebViewDelegate:self];

iOS 使用

// app监听js调用事件
[self.bridge registerHandler:@"jsCallAppFunc" handler:^(id data, WVJBResponseCallback responseCallback) {
  NSLog(@"jsCallAppFunc:, %@", data);
}];

//app 直接调用js方法
[self.bridge callHandler:@"appCallJsFunc" data:@{@"name": @"
js,我来自app"} responseCallback:^(id responseData) {
    NSLog(@"这是 js 又回传回来的数据:: %@", responseData);
}];

他主要是不懂js,下面是h5 的处理部分,直接上完整代码:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>js bridge test</title>
</head>

<body>

  //测试用
  <button onclick="btnClick()">点击调用app方法</button>
  <div>app 传给html的参数 显示在下面</div>
  <div id='cont'></div>

  <script>
    // 固定代码
    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 = 'wvjbscheme://__BRIDGE_LOADED__';
      document.documentElement.appendChild(WVJBIframe);
      setTimeout(function () { document.documentElement.removeChild(WVJBIframe) }, 0)
    }

    // 监听app 调用js 的事件
    setupWebViewJavascriptBridge(function (bridge) {
      bridge.registerHandler('appCallJsFunc', function (data, responseCallback) {
        // app的参数展示出来
        document.getElementById('cont').innerHTML = 'app传来参数:' + JSON.stringify(data)

        //下面这一段是回调给app的参数,无需求可以不调用
        // responseCallback({ 'subject': 'app,参数收好' })
      })
    })
    
    // js 主动去触发app的方法
    function btnClick() {
      setupWebViewJavascriptBridge(function (bridge) {
        bridge.callHandler('jsCallAppFunc', { 'title': '这是js传给app的参数' }, function (response) { 
          console.log('app 回调回来的参数')
        })
      })
    }
  </script>
</body>

</html>

测试了一下,双方通讯没有问题,可以直接使用。

后来他又说,以后用的地方可能会很多,能不能简单封装一下,想着闲来无事,简单封装一下吧。

// 独立出一个单独的js,方便各处引用:app.webview.bridge.js


; (() => {
  /**
   * app发送过来的 事件列表
   */
  const NativeEvent = [
    'appCallJsFunc'
  ]
  /**
   * 向app发送的 事件列表
   */
  const JSCallNativeEvent = [
    'jsCallAppFunc'
  ]

  /**
   * 固定的代码
   * */
  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 = 'wvjbscheme://__BRIDGE_LOADED__';
    document.documentElement.appendChild(WVJBIframe);
    setTimeout(function () { document.documentElement.removeChild(WVJBIframe) }, 0)
  }

  /**
   * 定义插件
   * */
  var _app_webview_ridge = {}

  /**
   * 注册app事件
   * */
  NativeEvent.map(event => {
    _app_webview_ridge[event] =   callback => {
      setupWebViewJavascriptBridge(bridge => {
        bridge.registerHandler(event, (data, responseCallback) => {
          callback(data, responseCallback)
        })
      })
    }
  })

  /**
   * 注册js事件
   * */
  JSCallNativeEvent.map(event => {
    _app_webview_ridge[event] = (data, callback)=> {
      setupWebViewJavascriptBridge((bridge) => {
        bridge.callHandler(event, data, response => {
          callback(response)
        })
      })
    }
  })
  /**
   * 定义插件的名称
   */
  this.appWebviewBridge = _app_webview_ridge;
})()


h5 使用就简单了

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>js bridge test</title>
  <script src="./app.webview.bridge.js"></script>
</head>

<body>

  //测试用
  <button onclick="btnClick()">点击调用app方法</button>
  <div>app 传给html的参数 显示在下面</div>
  <div id='cont'></div>

  <script>

    //可以查看整个对象有哪些方法可以调用
    console.log(appWebviewBridge)

    /**
     * 1,监听app的事件:appCallJsFunc,
     * 2,接受app的参数:data(app不传参数进来,data为空)
     * 3,处理完参数后,可以继续回传参数给app:responseCallback (非必要,可以不调用)
     * */
    appWebviewBridge.appCallJsFunc((data,responseCallback)=>{
      console.log('这是从app拿到的参数:' + JSON.stringify(data))
      document.getElementById('cont').innerHTML = 'app传来参数:' + JSON.stringify(data)
      // responseCallback({'title':'这是要给app的参数'})
    })

    /**
     * 1,js 主动触发app的方法
     * 2,{'name':"app,这是我给你的参数"} 是传给app的参数,(app不需要参数,可以为空)
     * 3,(res)=>{} app接到参数后又传回来的参数(可以不写)
    */
    function btnClick(){
      appWebviewBridge.jsCallAppFunc({'name':"app,这是我给你的参数"},(res)=>{
        console.log('app又给我参数了:' + JSON.stringify(res))
      })
    }
    
  </script>
</body>

</html>

因为我没有专门再起个iOS程序了,所以封装完直接丢给了他,后台他说可以直接使用,我也就没仔细测试了,有问题可以直接提给我,我再修改。