OC 和 JS 交互
- 传统上的交互使用:
- OC调用JS:
webView对象通过调用 stringByEvaluatingJavaScriptFromString 这个方法执行一段JS代码实现交互。这种方式对一些简单场景比较适用,也很方便
self.title = [self.webView stringByEvaluatingJavaScriptFromString:@"document.title"];
- JS调用OC:
webView拦截url链接,获取内容,再处理逻辑,实现以上webView的代理方法,webView每次开始加载URL时会进入这个方法,我们便可以在这个方法实现JS调用OC
这种JS调用OC的方法的缺点十分明显,需要繁琐地解释字符串得到相应的方法名和传值,且调用的方法也不能传递返回值;但优点是:不需要等待页面加载完才触发,当相应的代码被运行就能调用OC的方法
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
JS 端
function myFunction
{
window.location.href = @"iOS:shareToTest";
}
OC 端
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if ([@"iOS" isequalToString:request.URL.Scheme]) {
NSString *url = request.URL.absoluteString;
NSRange range = [url rangeOfStrng:@":"];
NSString *method = [request.URL.absoluteString substringFromIndex:range.location+1];
SEL selector = NSSelectorFromString(method);
if ([self respondsToSelector:selector]) {
[self performSelector:selector];
}
return NO;
}
return YES;
}
- (void)shareToTest {
NSLog(@"调用OC");
}
- 苹果推荐的框架--JavaScriptCore JavaScriptCore是苹果在iOS7时新推出用以实现JS和iOS代码交互的框架,十分简单高效,能够实现调用之后的回调处理,调用之后的回调处理,但是必须是html加载完成之后才可以
oc调用js时
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
//网页加载完成调用此方法
//首先创建JSContext 对象(此处通过当前webView的键获取到jscontext)
JSContext *context=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
NSString *alertJS=@"alert('test js OC')"; //准备执行的js代码
[context evaluateScript:alertJS];//通过oc方法调用js的alert
}
3. 优秀的第三方框架--WebViewJavascriptBridge
地址: https://github.com/marcuswestin/WebViewJavascriptBridge
WebViewJavascriptBridge同时支持UIWeView和WKWebView,无论是JS调用OC还是OC调用JS,都可以正常传值和返回值;而且在页面加载时只要JS代码被运行就可以进行交互
1、准备文件
ExamoleApp.html/JSBridgeVC.h/JSBridgeVC.m
2、js代码截取片段
这段代码是必须的,申明交互直接拷贝即可,处理交互部分,需要改动,关键就是和oc端协商的方法名,以及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)
}
<!-- 处理交互 方法名要和ios内定义的对应-->
setupWebViewJavascriptBridge(function(bridge) {
<!--处理 oc 调用 js -->
bridge.registerHandler('registerAction', function(data, responseCallback) {
//处理oc给的传参
alert('oc请求js 传值参数是:'+data)
var responseData = { 'result':'handle success' }
//处理完,回调传值给oc
responseCallback(responseData)
})
var callbackButton = document.getElementById('buttons').appendChild(document.createElement('button'))
callbackButton.innerHTML = '点击我,我会调用oc的方法'
callbackButton.onclick = function(e) {
e.preventDefault()
<!--处理 js 调用 oc -->
bridge.callHandler('loginAction', {'userId':'zhangsan','name': '章三'}, function(response) {
//处理oc过来的回调
alert('收到oc过来的回调:'+response)
})
}
})
3、OC代码
- pod导入框架
pod 'WebViewJavascriptBridge'
- import头部
#import "WebViewJavascriptBridge.h"
- viewDidload
//初始化 WebViewJavascriptBridge
if (_bridge) { return; }
[WebViewJavascriptBridge enableLogging];
_bridge = [WebViewJavascriptBridge bridgeForWebView:webView];
[_bridge setWebViewDelegate:self];
//请求加载html,注意:这里h5加载完,会自动执行一个调用oc的方法
[self loadExamplePage:webView];
//申明js调用oc方法的处理事件,这里写了后,h5那边只要请求了,oc内部就会响应
[self JS2OC];
//模拟操作:2秒后,oc会调用js的方法
//注意:这里厉害的是,我们不需要等待html加载完成,就能处理oc的请求事件;此外,webview的request 也可以在这个请求后面执行(可以把上面的[self loadExamplePage:webView]放到[self OC2JS]后面执行,结果是一样的)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self OC2JS];
});
- JS 调用 OC
-(void)JS2OC{
/*
含义:JS调用OC
@param registerHandler 要注册的事件名称(比如这里我们为loginAction)
@param handel 回调block函数 当后台触发这个事件的时候会执行block里面的代码
*/
[_bridge registerHandler:@"loginAction" handler:^(id data, WVJBResponseCallback responseCallback) {
// data js页面传过来的参数 假设这里是用户名和姓名,字典格式
NSLog(@"JS调用OC,并传值过来");
// 利用data参数处理自己的逻辑
NSDictionary *dict = (NSDictionary *)data;
NSString *str = [NSString stringWithFormat:@"用户名:%@ 姓名:%@",dict[@"userId"],dict[@"name"]];
[self renderButtons:str];
// responseCallback 给js的回复
responseCallback(@"报告,oc已收到js的请求");
}];
}
- OC 调用 JS
-(void)OC2JS{
/*
含义:OC调用JS
@param callHandler 商定的事件名称,用来调用网页里面相应的事件实现
@param data id类型,相当于我们函数中的参数,向网页传递函数执行需要的参数
注意,这里callHandler分3种,根据需不需要传参数和需不需要后台返回执行结果来决定用哪个
*/
//[_bridge callHandler:@"registerAction" data:@"我是oc请求js的参数"];
[_bridge callHandler:@"registerAction" data:@"uid:123 pwd:123" responseCallback:^(id responseData) {
NSLog(@"oc请求js后接受的回调结果:%@",responseData);
}];
}