zoukankan      html  css  js  c++  java
  • UIWebView中JS与OC交互 WebViewJavascriptBridge的使用

    一、综述

      现在很多的应用都会在多种平台上发布,所以很多程序猿们都开始使用Hybrid App的设计模式。就是在app上嵌入网页,只要写一份网页代码,就可以跑在不同的系统上。在iOS中,app多是通过WebView来加载网页,由于功能需求等原因,代码中少不得要和跟网页交互。

    二、原理

      在iOS中,本地调用Javascript语言,是通过UIWebView中的实例方法stringByEvaluatingJavaScriptFromString:来实现的,该方法通过字符串对象的形式传入JS代码。

    1
    [webView stringByEvaluatingJavaScriptFromString:@"Math.random();"];

       而JS调用本地的代码,则并没有现成的API,而是需要间接地通过一些方法来实现。我们利用UIWebView的代理方法,当UIWebView发起的所有网络请求,都可以通过delegate函数在Native层得到通知。这样,我们就可以在UIWebView内发起一个自定义的网络请求,比如:'wvjbscheme://__BRIDGE_LOADED__'。于是在UIWebView的delegate函数中,我们拦截url,只要发现是我们自定义的url,就不进行内容的加载,转而执行相应的调用逻辑。

    三、WebViewJavascriptBridge的使用

    1、WebViewJavascriptBridge简介

      WebViewJavascriptBridge支持到iOS6之前的版本的,用于支持native的iOS与javascript交互,接下来讲讲WebViewJavascriptBridge的基本原理及应该如何去使用,包括iOS端的使用和JS端的使用。

      首先,看看WebViewJavascriptBridge.m中Webview代理拦截的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener
    {
        if (webView != _webView) { return; }
         
        NSURL *url = [request URL];
        if ([_base isCorrectProcotocolScheme:url]) {
            if ([_base isBridgeLoadedURL:url]) {
                [_base injectJavascriptFile];
            else if ([_base isQueueMessageURL:url]) {
                NSString *messageQueueString = [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]];
                [_base flushMessageQueue:messageQueueString];
            else {
                [_base logUnkownMessage:url];
            }
            [listener ignore];
        else if (_webViewDelegate && [_webViewDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)]) {
            [_webViewDelegate webView:webView decidePolicyForNavigationAction:actionInformation request:request frame:frame decisionListener:listener];
        else {
            [listener use];
        }
    }

       WebViewJavascriptBridge是通过webview的代理拦截scheme,然后注入相应的JS,在拦截后,通过先通过-isBridgeLoadedURL:方法判断URL是否是需要bridge的URL,若是,则通过injectJavascriptFile方法注入JS;否则判断URL是否是队列消息,若是,则执行查询命令JS并刷新消息队列;如果都不匹配,URL被识别为未知的消息。

    2、WebViewJavascriptBridge的使用

      首先,要在JS中接入这个框架,这段代码是不变的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /**
     *  此为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函数要在下面函数中使用bridge.registerHandler来注册,而且JS需要调用的OC方法也要在下面的函数中用bridge.callHandler调用

    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    /**
     *  OC调用的JS函数需在此处注册,调用OC方法也需要在此处调用
     */
        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 + ':<br/>' + JSON.stringify(data)
                if (log.children.length) { log.insertBefore(el, log.children[0]) }
                else { log.appendChild(el) }
            }
                                      
            //注册一个给OC调用的函数,不带参数
            bridge.registerHandler('WebViewDidLoad',function() {
                log("WebViewDidLoad")
            })
             
            //注册一一个给OC调用的函数,接受OC传来的一个参数和一个回调处理
            bridge.registerHandler('OC_Call_JS', function(data, responseCallback) {
                log('oc调用js -', data)
                var responseData = { 'Javascript response':'oc调用JS成功!' }
                log('js被调用后响应-', responseData)
                responseCallback(responseData)
            })
     
            document.body.appendChild(document.createElement('br'))
     
            var callbackButton = document.getElementById('buttons').appendChild(document.createElement('button'))
            callbackButton.innerHTML = 'JS_Call_ObjC'
            callbackButton.onclick = function(e) {
                e.preventDefault()
                log('JS call OC')
                //此处调用OC方法
                bridge.callHandler('JS_Call_ObjC', {'foo''bar'}, function(response) {
                    log('JS call OC sucess and get OC rsp', response)
                })
            }
        })

      需要注意的是:在setupWebViewJavascriptBridge(function(bridge) {}函数体内的代码不能有错误,不然会导致不任何回调,不打印日志(JS的是脚本语言,跑到错的地方就不跑了)。

      OC部分,首先打开框架的日志系统,然后关联webView

    1
    2
    3
    [WebViewJavascriptBridge enableLogging];
         
        _bridge = [WebViewJavascriptBridge bridgeForWebView:webView];

       JS需要调用的OC方法,要在OC代码中注册

    1
    2
    3
    4
    [_bridge registerHandler:@"JS_Call_ObjC" handler:^(id data, WVJBResponseCallback responseCallback) {
            NSLog(@"JS调用OC: %@", data);
            responseCallback(@"OC被调用后响应:调用成功!");
        }];

       而想要调用JS中注册过的函数,在需要的地方用实例方法callHandler调用就可以了

    1
    2
    3
    4
    id data = @{ @"OC调用JS": @"Hi there, JS!" };
    [_bridge callHandler:@"OC_Call_JS" data:data responseCallback:^(id response) {
        NSLog(@"testJavascriptHandler responded: %@", response);
    }];

    四、小结

      最近因为项目需要,正在边学边做Hybrid App,刚好用到这个第三方,就写了篇文分享出来,希望能帮到刚刚入手的人,以上实例的demo地址https://github.com/GarenChen/WebViewJSBridgeDemo喜欢的顺手给个star ^_^;

    推荐一些阅读:

    JSBridge——Web与Native交互之iOS篇:http://www.jianshu.com/p/9fd80b785de1

    Hybrid App 开发模式:http://www.tuicool.com/articles/riE3Yn

    WebViewJavascriptBridge:https://github.com/marcuswestin/WebViewJavascriptBridge

  • 相关阅读:
    E
    D
    C
    B
    Python
    IDEA 设置资源目录
    光猫指示灯含义
    IO模型
    Linux 总目录
    Linux python 使用
  • 原文地址:https://www.cnblogs.com/sunfuyou/p/7658393.html
Copyright © 2011-2022 走看看