OC与JS交互—— UIWebView,WKWebView

iOS中用来加载网页,有两个控件UIWebView(iOS8之前),WKWebView(iOS8诞生)。WKWebView比UIWebView有太多的优势了,加载速度快,交互便捷等等。iOS8之后肯定要适配WKWebView。如果要适配到iOS7,项目里就必须要用这两个控件了。下面具体说一下这两个控件与JS的交互。

UIWebView交互Demo:http://onarkxpx4.bkt.clouddn.com/WebViewJavascriptBridgeDemo-master.zip

WKWebView交互Demo:http://onarkxpx4.bkt.clouddn.com/WKWebView与JS交互.zip

UIWebView交互

  • 代理方法交互 (自带方法)

拦截链接,从而获取链接里的信息,只能进行JS专递信息到OC。非常简陋,只适用超轻量级交互。

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
    
    //    NSLog(@"Scheme: %@", [url scheme]);  //方案
    //    NSLog(@"Host: %@", [url host]);    //主机
    //    NSLog(@"Port: %@", [url port]);    //端口
    //    NSLog(@"Path: %@", [url path]);    //路径
    //    NSLog(@"Relative path: %@", [url relativePath]); //相关路径
    //    NSLog(@"Path components as array: %@", [url pathComponents]);  //路径的每个组成部分
    //    NSLog(@"Parameter string: %@", [url parameterString]);   //参数
    //    NSLog(@"Query: %@", [url query]);                        //查询
    //    NSLog(@"Fragment: %@", [url fragment]);                  //分段

    //当前的链接
    NSURL* url = [request URL];
    NSString * string = [url absoluteString];
    //链接转为字典,获取我们想要的信息
    NSDictionary* dic = [self dictionaryFromQuery:string usingEncoding:NSUTF8StringEncoding];
    NSLog(@"%@",dic);
    //return NO 不允许跳转链接
    return YES;
    
}

链接转字典的工具方法

- (NSDictionary*)dictionaryFromQuery:(NSString*)query usingEncoding:(NSStringEncoding)encoding {
    NSCharacterSet* delimiterSet = [NSCharacterSet characterSetWithCharactersInString:@"&;"];
    NSMutableDictionary* pairs = [NSMutableDictionary dictionary];
    NSScanner* scanner = [[NSScanner alloc] initWithString:query];
    while (![scanner isAtEnd]) {
        NSString* pairString = nil;
        [scanner scanUpToCharactersFromSet:delimiterSet intoString:&pairString];
        [scanner scanCharactersFromSet:delimiterSet intoString:NULL];
        NSArray* kvPair = [pairString componentsSeparatedByString:@"="];
        if (kvPair.count == 2) {
            NSString* key = [[kvPair objectAtIndex:0]
                             stringByReplacingPercentEscapesUsingEncoding:encoding];
            NSString* value = [[kvPair objectAtIndex:1]
                               stringByReplacingPercentEscapesUsingEncoding:encoding];
            [pairs setObject:value forKey:key];
        }
    }
    
    return [NSDictionary dictionaryWithDictionary:pairs];
}
  • WebViewJavascriptBridge(第三方)
    传送门:https://github.com/marcuswestin/WebViewJavascriptBridge/

UIWebView给的原生方法里对OC与JS交互太乏力了。所以作为github上8千多star的第三方框架,WebViewJavascriptBridge作为UIWebView交互工具无疑是极为优秀的,使用也极为简单。

OC代码

JS调用OC方法(JS给OC传数据)

//基本设置
[WebViewJavascriptBridge enableLogging];//开启日志
WebViewJavascriptBridge* bridge = [WebViewJavascriptBridge bridgeForWebView:self.webView];
[bridge setWebViewDelegate:self];
//方法注册,AppClosePrice为方法名
[bridge registerHandler:@"AppClosePrice" handler:^(id data, WVJBResponseCallback responseCallback) {
        //data为JS传来的数据
        NSLog(@"%@", data);
        [self.navigationController popViewControllerAnimated:YES];
        
    }];

** OC调用JS方法(OC给JS传数据,也可以接收JS传过来的数据)**
基本设置同上,就是注册方法的时候不同。

//AppHidden:方法名,appCurVersion:OC给JS传的数据
[self.bridge callHandler:@"AppHidden" data:appCurVersion responseCallback:^(id responseData) {

        NSLog(@"----JS传过来的数据----%@",responseData);
    }];

JS代码(由后台实现,可以给后台参考)

 /*这段代码是固定的,必须要放到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 = 'wvjbscheme://__BRIDGE_LOADED__';
        document.documentElement.appendChild(WVJBIframe);
        setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
      }
    
      /*与OC交互的所有JS方法都要放在此处注册,才能调用通过JS调用OC或者让OC调用这里的JS*/
      setupWebViewJavascriptBridge(function(bridge) {
       var uniqueId = 1
                                   
       function log(message, data) {
         var log = document.getElementById('log')
         var el = document.createElement('div')
         el.className = 'logLine'
         el.innerHTML = uniqueId++ + '. ' + message + ':
' + JSON.stringify(data) if (log.children.length) { log.insertBefore(el, log.children[0]) } else { log.appendChild(el) } } /* Initialize your app here */ /*注册一个JS调用OC的方法,不带参数*/ bridge.registerHandler('AppClosePrice', function() { log("JS调用OC") }) /*注册一个JS调用OC的方法,带参数*/ bridge.registerHandler('AppClosePrice', function(data, responseCallback) { log("Get user information from OC: ", data) }) /*注册一个OC调用JS的方法*/ bridge.callHandler('AppHidden', function(responseData) { log("JS call ObjC's getUserIdFromObjC function, and js received response:", responseData) })

WKWebView交互

WKWebView作为UIWebView的替代品,具有完备的JS交互方法,我们可以不借助第三方,就进行OC与JS的深度交互。并且JS端的代码也极其简易。

JS调用OC方法(JS给OC传数据)

交互的方法名定义好,OC,JS都需要进行注册。

OC端注册方法(IOSClosePrice)

    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    config.userContentController = [[WKUserContentController alloc] init];
    [config.userContentController addScriptMessageHandler:self name:@"IOSClosePrice"];
    WKWebView *webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - 14) configuration:config];

JS端注册方法(IOSClosePrice)

function payClick() {
        window.webkit.messageHandlers.IOSClosePrice.postMessage({order_no:'201511120981234',channel:'wx',amount:1,subject:'粉色外套'});
    }

OC端接收数据

WKWebView的协议WKScriptMessageHandler里面的方法,JS向OC传任何数据,OC都可以通过该方法接收,通过JS传过来的数据,我们可以调用相应OC的方法,从而达到JS调用OC方法的目的。

/**
 * JS给原生传数据:JS调用原生的方法
 */
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
    
    NSDictionary *dict = message.body;
    NSString* action = [dict valueForKey:@"action"];
    NSLog(@"----WKwebView交互----%@",action);
    
    if ([action isEqualToString:@"action1"]) {
        [self action1];
    }

    if ([action isEqualToString:@"action2"]) {
        [self action2];
    }
}

OC调JS的方法(OC向JS传数据)

OC端代码

payResult 为规定好的方法名,JS端用这个方法名接收数据。

    // 将支付结果返回给js
    //这里的payResult()是JS的语言
    NSString *jsStr = [NSString stringWithFormat:@"payResult('%@')",@"支付成功"];
    [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        NSLog(@"%@----%@",result, error);
    }];

注意:当JS调用OC的时候也可以用这个方法给JS进行回传数据,和上面的WKScriptMessageHandler代理中的方法相结合,就是实现了OC和JS的数据交流

JS端代码

function payResult(str) {
                asyncAlert(str);
                document.getElementById("returnValue").value = str;
            }

总结

从上面分析可以看出,UIWebView作为古老的网页加载控件,只能靠三方才能进行方便的JS交互,虽然WebViewJavascriptBridge使用起来很方便,但是局限性还是有的。而WKWebView作为UIWebView的替代。在OC与JS交互上面体现了强大的能力。WKWebView更注重的加强了OC和JS之间的数据通讯。双方的代码量都极为简洁,数据交互也一目了然。

你可能感兴趣的:(OC与JS交互—— UIWebView,WKWebView)