一、综述

  现在很多的应用都会在多种平台上发布,所以很多程序猿们都开始使用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

UIWebView中JS与OC交互 WebViewJavascriptBridge的使用的更多相关文章

  1. 史上最全的 UIWebview 的 JS 与 OC 交互

    来源:伯乐在线 - 键盘风筝 链接:http://ios.jobbole.com/89330/ 点击 → 申请加入伯乐在线专栏作者 其实一直想给大家整理一下JS与OC的交互,但是没有合适的机会,今天借 ...

  2. iOS UIWebView 中 js调用OC 打开相册 获取图片, OC调用js 将图片加载到html上

    线上html <!DOCTYPE html> <html> <head> <title>HTML中用JS调用OC方法</title> < ...

  3. UIWebView与JS的深度交互

    我要实现这样一个需求:按照本地的CSS文件展示一串网络获取的带HTML格式的只有body部分的文本,需要自己拼写完整的 HTML.除此之外,还需要禁用获取的HTML文本中自带的 < img &g ...

  4. UIWebView与JS的深度交互-b

    要实现这样一个需求:按照本地的CSS文件展示一串网络获取的带HTML格式的只有body部分的文本,需要自己拼写完整的 HTML.除此之外,还需要禁用获取的HTML文本中自带的 < img > ...

  5. JS与OC交互--简单使用

    直接上代码 .m文件 #import "ViewController.h" @interface ViewController () <UIWebViewDelegate&g ...

  6. MXBridge - 插件式JS与OC交互框架

    概述 MXBridge,提供一个插件式的JavaScript与Objective-C交互的框架,通过JavaScriptCore实现,插件式扩展Obejctive-C接口以供JavaScript调用. ...

  7. 转载 【iOS开发】网页JS与OC交互(JavaScriptCore) OC ----->JS

      目标 本文介绍利用苹果在iOS7时发布的JavaScriptCore.framework框架进行js与OC的交互.我们想要达到的目标是: OC调用网页上的js方法 网页js调用APP中的OC方法 ...

  8. IOS的UIWebView中JS点击事件,需要加入cursor:pointer;属性才可以

    IOS的UIWebView中JS点击事件,需要加入cursor:pointer;属性才可以. Android的WebView可以支持外链样式,js文件:IOS则需要改为内嵌样式和JS文件.

  9. iOS中JS 与OC的交互(JavaScriptCore.framework)

    iOS中实现js与oc的交互,目前网上也有不少流行的开源解决方案: 如:react native 当然一些轻量级的任务使用系统提供的UIWebView 以及JavaScriptCore.framewo ...

随机推荐

  1. 【SqlServer】在SqlServer中把数据导入导出为Excel文件

    这里笔者介绍利用SqlServer数据库操作EXECEL文件. 1.将Excel表中的数据导入为SqlServer数据库 把Excel表中的数据导入为SqlServer数据库中的数据. 新建一个Exc ...

  2. 使用SQL Server发送邮件时遇到的诡异事件

    最近公司要实现一个邮件群发的功能,因此设计时就考虑用SQL Server的邮件发送功能直接推送邮件算了. 可是在实现的过程中,邮件内容中有一个表格的内容要展现,于是就编排了一个表格来实现. 具体实现如 ...

  3. 高并发分布式系统中生成全局唯一(订单号)Id js返回上一页并刷新、返回上一页、自动刷新页面 父页面操作嵌套iframe子页面的HTML标签元素 .net判断System.Data.DataRow中是否包含某列 .Net使用system.Security.Cryptography.RNGCryptoServiceProvider类与System.Random类生成随机数

    高并发分布式系统中生成全局唯一(订单号)Id   1.GUID数据因毫无规律可言造成索引效率低下,影响了系统的性能,那么通过组合的方式,保留GUID的10个字节,用另6个字节表示GUID生成的时间(D ...

  4. Oracle 12C -- shutdown CDB

    SQL> select name,open_mode from v$pdbs; NAME OPEN_MODE ------------------------------ ---------- ...

  5. Failed to resolve: 之一

    摘要:编译不通过提示错误如下:gradle文件里边对应:解决方案:在gradle文件里边加上.+,解决后gradle文件如下图所示:然后编译就能通过. 解决方案: 在gradle文件里边加上.+,解决 ...

  6. Java/Android倒计时(开始,暂停,恢复,停止)

    由于要做暂停和恢复,这里我就没有使用Android的CountDownTimer,而是用了Java的Timer.所以,这个方法在java肯定是通用.我也外加了Android独有的Service,有些计 ...

  7. 源码安装mysql 5.7.19数据库

    1.系统要求yum install -y cmake make gcc gcc-c++ bison  ncurses ncurses-devel 2.创建用户和组groupadd mysql & ...

  8. Debian静态IP地址和DNS

    Debian静态IP地址和DNS 一.配置文件及路径 /etc/network/interfaces 二.IP地址1. DHCP的IP配置如下 # The primary network interf ...

  9. weblogic+eclipse插件部署多个项目

    第一篇博客...上班时间不多废话,直接上图. 首先环境我就不说了,装好weblogic,eclipse,以及weblogic的插件. eclipse的weblogic插件能够从eclipse上的Hel ...

  10. [转]Filter 过滤器

    1.简介 Filter也称之为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 ...