JS和OC交互

JavaScriptCore和原生页面交互


主要主要总结一下利用JavaScriptCore和UIWebView交互过程中遇到的问题。分三部分讲解

  1. JS调用原生
  2. OC调用JS
  3. 传值

JSContext可以将它视为一个盒子(字典),盒子中装了所有的webview加载的网页的代码(和H5的document对象好像),通过这个JSContext对象可以拿到盒子中的任意一个元素或者JS方法(通过方法名字符串),JSContext拿出来的东西 是JSValue对象。JSValue对象是对js中的对象或者方法进行的封装。

JS调用原生方法

首先导入JavaScriptCore,初始化webview,实现webview代理方法,然后再代理方法- (void)webViewDidFinishLoad:(UIWebView *)webView中实现初始化JSContext对象代码如下:

//对JSContext对象进行初始化
    self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
  1. 利用block进行的调用
    self.context[@"webAudio"] = ^(NSString *speakingWords){
        NSLog(@"speakingwords====%@",speakingWords);
    };

其中webAudio为js中的方法名 block的参数为js调用webAudio方法的时候给webAudio方法传递的参数,相当于将js的方法直接用block替换了。所以在JS调用JS的webAudio方法的时候,实际是在调用block,OC中可以在block中实现调用OC的方法,完成JS调用OC方法。

  1. 利用协议JSExport
    一. 将JS中JS方法的调用者设置为控制器对象。
    二. 自定义一个协议继承自JSExport协议,并定义OC中将调用的方法
self.context[@"wjyg"] = self;
@protocol WebExpert 
JSExportAs(toPage, -(void)jumpToSpeakingView:(NSString*)passWords);
@end

JS代码如下

  function toPageForWJYG(data){
        try {
            window.wjyg && wjyg.toPage(data);
        } catch(e){
            alert(e.message);
        }
    }

JS中通过调用wjyg对象的toPage方法进行传值,第一步将controller对象赋值给js中的wjyg对象,相当于将对象进行了替换。
第二步,实现协议 将toPage方法替换为了controller中的-(void)jumpToSpeakingView:(NSString)passWords。
之后js调用wjyg.toPage(data)的时候,相当于controller调用了
controller的-(void)jumpToSpeakingView:(NSString
)passWords方法,


OC调用JS方法

一 .通过利用context和JS方法名字符串拿到JSValue包装的JS方法(也就是JSValue对象)
二 . JSValue对象调用JSValue的方法就可以了(主要方法是callWithArguments:)。

JSValue   *permissionValue = self.context[@"getListenPermission"];
[permissionValue callWithArguments:@[@"true"]];

OC之间传值

在以上的方法调用之间有值的传递。仔细看代码。



JavaScriptBridge和OC交互

JavaScriptBridge说白了就相当于一个中间人,注册方法和调用方法就像卖东西和买东西,注册方法相当于卖家告诉bridge自己有某个东西,调用方法就像是买家告诉bridge自己就想买某个东西


需要在js中加入代码

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)
}

在OC中调用的时候注意一下问题

  1. 给webivew设置bridge需要在webview创建之后就可以(另外不能重复设置也就是如下代码只调用一次就行了)
_bridge = [WebViewJavascriptBridge bridgeForWebView:_webView];
 [_bridge  setWebViewDelegate:self];
  1. JS调用原生的时候,原生register方法的时机(也就是registerhander的方法应该放在webviewloadfinish代理方法中).因为要等到所有js文件加载完成之后才能想bridge注册方法.

  2. js端调用代码的时候不能通过ID获取已存在的button变量并添加onclick事件,这样会导致客户端点击按钮的时候第一次点击没有效果(注册事件的回调block不走),可以在点击事件中直接调用

setupWebViewJavascriptBridge(function(bridge) {
                bridge.callHandler('checkLoginWithUrl',{'hrefStr':"http://www.baidu.com?"}, function(response) {
                })
        })
        setupWebViewJavascriptBridge(function(bridge) {
            bridge.callHandler('checkLogin', function(response) {
            })
        })

你可能感兴趣的:(JS和OC交互)