一、iOS中的WebView

在 iOS 开发 Hybrid App 的时分,有两个 WebView 能够选择:

  • UIWebView
  • WKWebView

这两个 WebView 控件,能够彻底只凭借 iOS 自带的结构进行 OC & JS 交互。

  1. UIWebView 运用 JavaScriptCore.
  2. WKWebView 运用 WKUserContentController.

二、WebView 与 原生的交互原理

UIWebView 原生的交互原理
经过一个 JSContext 获取 UIWebView 的 JS 履行上下文。
然后经过这个上下文,进行 OC & JS 的双端交互。

_jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
_jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) {
    NSLog(@"%@",@"获取 WebView JS 履行环境失败了!");
};

WKWebView 原生交互原理

经过 userContentController 把需求调查的 JS 履行函数注册起来。
然后经过一个协议办法,将所有注册过的 JS 函数履行的参数传递到此协议办法中。

注册 需求 调查的 JS 履行函数

[webView.configuration.userContentController addScriptMessageHandler:self name:@"jsFunc"];

在 JS 中调用这个函数并传递参数数据

window.webkit.messageHandlers.jsFunc.postMessage({name : "李四",age : 22});

OC 中遵守 WKScriptMessageHandler 协议。

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message

此协议办法里的 WKScriptMessage 有 name & body 两个特点。 name 能够用来判别是哪个 JSFunc 调用了。body 则是 JSFunc 传递到 OC 的参数。


三、WebViewJavaScriptBridge

WebViewJavaScriptBridge 用于 WKWebView & UIWebView 中 OC 和 JS 交互。
它的根本原理是:

把 OC 的办法注册到桥梁中,让 JS 去调用。
把 JS 的办法注册在桥梁中,让 OC 去调用。

WebViewJavascriptBridge 根本原理

01-H5与Native交互-JS与Native互调|WebViewJavaScriptBridge 基本使用(转)

注册自己,调用它人。


四、WebViewJavaScriptBridge 运用的根本过程

  1. 首要在项目中导入 WebViewJavaScriptBridge 结构
pod ‘WebViewJavascriptBridge’
  1. 导入头文件 #import <WebViewJavascriptBridge.h>
  2. 树立 WebViewJavaScriptBridge 和 WebView 之间的联系。
_jsBridge = [WebViewJavascriptBridge bridgeForWebView:_webView];
  1. 在HTML 文件中,复制粘贴这两段 JS 函数。

function setupWebViewJavascriptBridge(callback) {
        if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
        if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
        window.WVJBCallbacks = [callback]; // 创建一个 WVJBCallbacks 全局特点数组,并将 callback 刺进到数组中。
        var WVJBIframe = document.createElement('iframe'); // 创建一个 iframe 元素
        WVJBIframe.style.display = 'none'; // 不显示
        WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__'; // 设置 iframe 的 src 特点
        document.documentElement.appendChild(WVJBIframe); // 把 iframe 添加到当时文导航上。
        setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
    }
    // 这儿用于注册 Native 将要调用的 JS 办法。
    setupWebViewJavascriptBridge(function(bridge){
    });

到此为止,根本的准备工作就做完了。现在需求往桥梁中注入 OC 办法 和 JS 函数了。


往桥梁中注入 OC 办法 和 JS 函数

往桥梁中注入 OC 办法。

[_jsBridge registerHandler:@"scanClick" handler:^(id data, WVJBResponseCallback responseCallback) {
    NSLog(@"dataFrom JS : %@",data[@"data"]);
    responseCallback(@"扫描成果 : www.baidu.com");
}];

这段代码的意思:

  1. scanClick 是 OC block 的一个别名。
  2. block 自身,是 JS 经过某种办法调用到 scanClick 的时分,履行的代码块。
  3. data ,由于 OC 这端由 JS 调用,所以 data 是 JS 端传递过来的数据。
  4. responseCallback OC 端的 block 履行完毕之后,往 JS 端传递的数据。

往桥梁中注入 JS 函数.

OC 办法,在 OC 中注入。JS 的办法所以必然就需求在 JS 中注入的。(好像是废话)
在 JS 的办法如何注入到桥梁呢?

之前,在准备工作的时分,有两段 JS 代码。
需求在第二段 JS 代码中,注入 JS 的函数。


// 这儿主要是注册 OC 将要调用的 JS 办法。
    setupWebViewJavascriptBridge(function(bridge){
        // 声明 OC 需求调用的 JS 办法。
        bridge.registerHanlder('testJavaScriptFunction',function(data,responseCallback){
            // data 是 OC 传递过来的数据.
            // responseCallback 是 JS 调用完毕之后传递给 OC 的数据
            alert("JS 被 OC 调用了.");
            responseCallback({data: "js 的数据",from : "JS"});
        })
    });

这段代码的意思:

  1. testJavaScriptFunction 是注入到桥梁中 JS 函数的别名。以供 OC 端调用。
  2. 回调函数的 data。 既然 JS 函数由 OC 调用,所以 data 是 OC 端传递过来的数据。
  3. responseCallback 。 JS 调用在被 OC 调用完毕之后,向 OC 端传递的数据。

根本便是:

OC 端注册 OC 的办法,OC 端调用 JS 的函数。
JS 端注册 JS 的函数,JS 端调用 OC 的办法。

五、原生与Web互调场景

1.JS -> OC 的交互

在 HTML 中,有个按钮,点击这个按钮,修正 NavigationBar 的色彩。

  1. 在 OC 端,往桥梁注入一个修正 NavigationBar 色彩的 block.
  2. 在 JS 端,调用这个 block,来直接的到达修正色彩的目的。

01-H5与Native交互-JS与Native互调|WebViewJavaScriptBridge 基本使用(转)

首要,在 OC 中,经过 WebViewJavascriptBridge 注册一个修正 navigationBar 色彩的 Block。

[_jsBridge registerHandler:@"colorClick" handler:^(id data, WVJBResponseCallback responseCallback) {
       self.navigationController.navigationBar.barTintColor = [UIColor colorWithRed:arc4random_uniform(256) / 255.0 green:arc4random_uniform(256) / 255.0 blue:arc4random_uniform(256) / 255.0 alpha:1.0];
        responseCallback(@"色彩修正完毕!");
    }];

然后再 JS 中,经过某种办法去调用这个 OC 的 block。

WebViewJavascriptBridge.callHandler('colorClick',function(dataFromOC) {
    alert("JS 调用了 OC 注册的 colorClick 办法");
    document.getElementById("returnValue").value = dataFromOC;
})

这儿经过某种办法便是运用 WebViewJavascriptBridge.callHandler(‘OC 中block 别名’,callback) 的办法来调用。

2.OC -> JS 的交互

OC 上有一个UIButton,点击这儿按钮,把 HTML body 的色彩修正成橙色。

首要,往桥梁中,注入一个修正 HTML body 色彩的 JSFunction。

// 在这儿声明 OC 需求自动调用 JS 的办法。
setupWebViewJavascriptBridge(function(bridge) { 
      bridge.registerHandler('changeBGColor',function(data,responseCallback){
            // alert('aaaaaa');
            document.body.style.backgroundColor = "orange";
            document.getElementById("returnValue").value = data;
    });
}); 

然后在 OC 端经过桥梁调用这个 changeBGColor

[_jsBridge callHandler:@"changeBGColor" data:@"把 HTML 的布景色彩改成橙色!!!!"];

履行效果:

01-H5与Native交互-JS与Native互调|WebViewJavaScriptBridge 基本使用(转)


六、补充

OC 调用 JS 的三种状况。

    // 单纯的调用 JSFunction,不往 JS 传递参数,也不需求 JSFunction 的返回值。
    [_jsBridge callHandler:@"changeBGColor"];
    // 调用 JSFunction,并向 JS 传递参数,但不需求 JSFunciton 的返回值。
    [_jsBridge callHandler:@"changeBGColor" data:@"把 HTML 的布景色彩改成橙色!!!!"];
    // 调用 JSFunction ,并向 JS 传递参数,也需求 JSFunction 的返回值。
    [_jsBridge callHandler:@"changeBGColor" data:@"传递给 JS 的参数" responseCallback:^(id responseData) {
        NSLog(@"JS 的返回值: %@",responseData);
    }];

JS 调用 OC 的三种状况。


// JS 单纯的调用 OC 的 block
WebViewJavascriptBridge.callHandler('scanClick');
// JS 调用 OC 的 block,并传递 JS 参数
WebViewJavascriptBridge.callHandler('scanClick',"JS 参数");
// JS 调用 OC 的 block,传递 JS 参数,并承受 OC 的返回值。
WebViewJavascriptBridge.callHandler('scanClick',{data : "这是 JS 传递到 OC 的扫描数据"},function(dataFromOC){
    alert("JS 调用了 OC 的扫描办法!");
    document.getElementById("returnValue").value = dataFromOC;
});

能够根据实际状况,选择合适的办法。

关于在 OC 中,往桥梁中注入 block 的注意点。

在当时控制器消失的时分,要记得把注入到桥梁中的 OC block,从桥梁中删除。
不然,可能会出现控制器无法开释的状况。

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    [_jsBridge removeHandler:@"scanClick"];
    [_jsBridge removeHandler:@"colorClick"];
    [_jsBridge removeHandler:@"locationClick"];
    [_jsBridge removeHandler:@"shareClick"];
    [_jsBridge removeHandler:@"payClick"];
    [_jsBridge removeHandler:@"goBackClick"];
}

最终总结:

  1. UIWebView & JavaScriptCore 等于原生的 JS & OC 交互方案。
  2. WKWebView & userContentController 等于原生了 JS & OC 交互方案。
  3. WebViewJavascriptBridge 能够调配 UIWebView & WKWebView 进行 OC & JS 交互。
  4. WebViewJavascriptBridge 运用核心,OC 注入 OC 的办法,让 JS 调用。JS 注入 JS 函数,让 OC 调用。
  5. WebViewJavaScriptBridge 运用的需求 4个前提过程。
  • Demo

引荐阅览

  • JSBridge原理解析——以WebviewJavascriptBridge实现办法为例
  • 运用 JSBridge 与原生 IOS、Android 进行交互(含 H5、Android、IOS 端代码,附 Demo)
  • WKWebView所有API详解