为什么要交互?
在实际项目中往往会使用到页面中内嵌wap页的情况,这样做能减少开发工作量,且只要修改wap页就能同步改变iOS端页面的内容,很方便。虽然iOS
实际工程中常希望在点击wap页面内容时不使用wap页本身的跳转,而是跳转到项目中的另一个页面,就需要在JS中调用iOS端中类似以下的方法进行跳转或执行一些其他操作
[self.navigationController pushViewController:ViewController animated:YES];
有时也有可能通过iOS端的方法来调用JS中的方法来实现一些功能
所以就需要实现在JS和iOS端之间进行 交配 交互
在iOS8中新增的WKWebView框架带有Nitro JavaScript引擎,正在逐步取代WebView框架,为了向下适配iOS7的用户所以工程里还是用了UIWebView。
相关的iOS原生方法
1.UIWebView的代理方法
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
在WebView中的wap页将要载入内容时得到通知触发,返回NO则阻止加载内容,
- 优点:简单易用,在页面跳转请求时进行iOS端的页面跳转,并返回NO阻止wap内的页面跳转
- 缺点:无法识别不加载新内容的JS动作(点击按钮弹出对话框和提交等)
这里比较推荐用方法1,方法2需要JS基础,不太懂得前端开发的程序员慎用
2.运用JavaScriptCore框架进行交互
- JS中调用OC方法
//获取当前的JS环境
JSContext* context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//----------------------------------------------------------------------------------------------------------------
//用block定义要被JS调用的方法
NSNumber* (^do_something)(void) = ^(void){
BOOL singleDog = [programmer isSingle];
int someData = singleDog?1:-1;
return [NSNumber numberWithInt:someData];//数据类型应为Number,此时即为OC向JS传值
};
//在JS中添加了一个方法指针 do_something
context[@"do_something"] = do_something;
该方法常在以下UIWebView的代理方法中使用,在页面加载完毕时向JS中添加
- (void)webViewDidFinishLoad:(UIWebView *)webView
- OC中调用JS方法
[myWebView stringByEvaluatingJavaScriptFromString:@"JS中的方法"];
暂时不会写JS,具体例子请参考这里
第三方框架 WebViewJavascriptBridge
该框架的主要使用方法是在iOS端中先创建一个WebViewJavascriptBridge对象,并运用该对象实现交互
首先要在JS中添加如下方法
function connectWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) {
callback(WebViewJavascriptBridge)
} else {
document.addEventListener('WebViewJavascriptBridgeReady', function() {
callback(WebViewJavascriptBridge)
}, false)
}
connectWebViewJavascriptBridge(function(bridge) {
//注意,你的bridge函数都应写在这里面
}
//例如
function doSomething(){
connectWebViewJavascriptBridge(function(bridge) {
bridge.init(function(message, yourCallback) {
log('ObjC called testJavascriptHandler with', message)
var responseData = { 'Javascript Says':'Right back atcha!' }
log('JS responding with', responseData)
responseCallback(responseData)
})
}
}
OC调用JS方法
1.调用JS中bridge.init的方法
//OC
[_bridge send:@"The message sent from ObjC to JS" responseCallback:^(id response) {
NSLog(@"sendMessage got response: %@", response);//这里的response是js方法中的data
}];
//对应调用js中的方法
bridge.init(function(message, yourCallback) {
log('ObjC called testJavascriptHandler with', message)
var responseData = { 'Javascript Says':'Right back atcha!' }
log('JS responding with', responseData)
responseCallback(responseData)
})
2.调用JS中bridge.registerHandler方法,该方法可以注册方法名,通过注册名确认调用方法
//OC
[_bridge callHandler:@"注册名" data:data responseCallback:^(id response) {
NSLog(@"testJavascriptHandler responded: %@", response);
}];
//对应调用的js中的方法
bridge.registerHandler('注册名', function(data, responseCallback) {
log('ObjC called testJavascriptHandler with', data)
var responseData = { 'Javascript Says':'Right back atcha!' }
log('JS responding with', responseData)
responseCallback(responseData)
})
JS端调用OC端方法
1.调用OC中创建bridge对象时定义时的方法
//JS中
bridge.send(data,function(response){
log('这里是回调方法',response) //回调方法
})
//对应调用的OC中bridge初始化中设置的block方法
_bridge = [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) {
//do something...
NSLog(@"ObjC received message from JS: %@", data);//从js获得的参数
responseCallback(@"Response");//Response to js
}];
2.通过方法名调用OC中bridge的注册方法
//JS中
bridge.callHandler('注册名', {'foo': 'bar'}, function(response) {
log('JS got response', response)
})
//对应调用的OC中的bridge注册的方法
[_bridge registerHandler:@"注册名" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"testObjcCallback called: %@", data);//从js获取的参数
responseCallback(@"Response");//
}];