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
UIWebView中JS与OC交互 WebViewJavascriptBridge的使用的更多相关文章
- 史上最全的 UIWebview 的 JS 与 OC 交互
来源:伯乐在线 - 键盘风筝 链接:http://ios.jobbole.com/89330/ 点击 → 申请加入伯乐在线专栏作者 其实一直想给大家整理一下JS与OC的交互,但是没有合适的机会,今天借 ...
- iOS UIWebView 中 js调用OC 打开相册 获取图片, OC调用js 将图片加载到html上
线上html <!DOCTYPE html> <html> <head> <title>HTML中用JS调用OC方法</title> < ...
- UIWebView与JS的深度交互
我要实现这样一个需求:按照本地的CSS文件展示一串网络获取的带HTML格式的只有body部分的文本,需要自己拼写完整的 HTML.除此之外,还需要禁用获取的HTML文本中自带的 < img &g ...
- UIWebView与JS的深度交互-b
要实现这样一个需求:按照本地的CSS文件展示一串网络获取的带HTML格式的只有body部分的文本,需要自己拼写完整的 HTML.除此之外,还需要禁用获取的HTML文本中自带的 < img > ...
- JS与OC交互--简单使用
直接上代码 .m文件 #import "ViewController.h" @interface ViewController () <UIWebViewDelegate&g ...
- MXBridge - 插件式JS与OC交互框架
概述 MXBridge,提供一个插件式的JavaScript与Objective-C交互的框架,通过JavaScriptCore实现,插件式扩展Obejctive-C接口以供JavaScript调用. ...
- 转载 【iOS开发】网页JS与OC交互(JavaScriptCore) OC ----->JS
目标 本文介绍利用苹果在iOS7时发布的JavaScriptCore.framework框架进行js与OC的交互.我们想要达到的目标是: OC调用网页上的js方法 网页js调用APP中的OC方法 ...
- IOS的UIWebView中JS点击事件,需要加入cursor:pointer;属性才可以
IOS的UIWebView中JS点击事件,需要加入cursor:pointer;属性才可以. Android的WebView可以支持外链样式,js文件:IOS则需要改为内嵌样式和JS文件.
- iOS中JS 与OC的交互(JavaScriptCore.framework)
iOS中实现js与oc的交互,目前网上也有不少流行的开源解决方案: 如:react native 当然一些轻量级的任务使用系统提供的UIWebView 以及JavaScriptCore.framewo ...
随机推荐
- webpack window 安装loader
1.安装loadernpm install css-loader style-loader --save-dev 2.配置loader,在webpack.config.js中 module: { lo ...
- Java使用Itext5.5.10进行pdf签章
说到PDF数字签名签章,这个其实也是数字证书信息安全的应用范畴,关于数字证书和数字签名,网上有很多解释说明,但讲解都多不够详细准确,这边推荐一篇大神的博文,讲解浅显易懂形象数字证书 数字签名 数据加密 ...
- 百度OCR识别示例
文章地址:https://www.cnblogs.com/Charltsing/p/OcrAnswerer.html 最新版为v4.1版,开放一定概率的八窗口体验功能,请截图体验(多点几次图片).更新 ...
- Linux/Unix 新手和专家教程
你正在找一些高质量的Linux 和 UNIX 的教程吗?如果是,这篇文章会告诉你到哪去找到这些教程.这里我们将给出超过30个相当的不错的 Linux 和 UNIX 在线的教程. 需要大家注意的是,他们 ...
- 利用AutoSPSourceBuilder和Autospinstaller自动安装SharePoint Server 2013图解教程——Part 1
这是一篇对之前 <利用AutoSPSourceBuilder和Autospinstaller自动安装SharePoint Server 2013图解教程——Part 2>的补充.本篇博客将 ...
- Android RoboGuice开源框架、Butter Knife开源框架浅析
Google Guice on Android(RoboGuice) 今天介绍一下Google的这个开源框架RoboGuice, 它的作用跟之前讲过的Dagger框架差点儿是一样的,仅仅是Dagger ...
- 设计模式C++实现——模板方法模式
模式定义: 模板方法模式在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类能够在不改变算法结构的情况下,又一次定义算法中的某些步骤. 模板就是一个方法.更详细的说.这种方法将 ...
- [转]Spring注解-@Configuration注解、@Bean注解以及配置自动扫描、bean作用域
1.@Configuration标注在类上,相当于把该类作为spring的xml配置文件中的<beans>,作用为:配置spring容器(应用上下文) package com.test.s ...
- windows 64位下,React-Native环境搭建详解 (Android)
React-Native环境搭建需要: 1.安装Java JDK 2.安装Android Studio 3.安装node.js 4.安装git 5.安装Python 2.x (注意目前不支持Pytho ...
- cent os 6.5 配置vsftpd
1. 下载vsftpd: #yum –y install vsftpd 2. 关闭iptables 查看防火墙状态:/etc/init.d/iptables status 关闭:service ipt ...