看简书上说一共有六种OC和JS交互的方法,但是前三种原理都一致,都是通过检测、拦截Url地址实现互相调用的。剩下的react native等第三方框架原理不一样,也没有去研究,下边记录我使用的三种方法(原理都是拦截Url地址)。
(一)、使用系统自带JavaScriptCore库进行交互,支持iOS7以后系统。(备注:我这个项目在交互MBProgress的时候控制隐藏,js代码会发生奔溃,安卓是好的,原因始终找不到)
oc调用js方法
[homeWebView stringByEvaluatingJavaScriptFromString:jsFunction];
-------------------------------------------------------------------
js调用oc方法导入
1、JavaScriptCore库
#import <JavaScriptCore/JavaScriptCore.h>
2、获得上下文
- (void)webViewDidFinishLoad:(UIWebView *)webView{
//降低webview带来的内存泄露
[[NSUserDefaultsstandardUserDefaults] setInteger:0forKey:@"WebKitCacheModelPreferenceKey"];
//----------------------JS回掉方法----------------------------------------
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//没有返回值的写法
context[@"showProgressDialogPhone"] = ^() { // 显示
[self showProgressDialog];
};
// 有返回值的写法,
context[@"getTabInfoIOS"] = [self getTabInfoIOS];//获得权限
}
3、js端绑定方法oc方法,绑定的这个方法名称必须要和oc里注册的方法名称保持一致
function showProgressDialog(){
showProgressDialogPhone();
}
(二)、实现了JSExport协议的协议,这样调用到vc里的方法
1、声明协议,实现协议方法
在.h文件中声明
@protocol TestJSObjectProtocol <JSExport>
-(void)closeProgressDialog;
@end
.m文件中实现协议方法
@interface ViewController ()<TestJSObjectProtocol>
@end
1、同上先获得上下文,oc这里绑定方法、实现closeProgressDialog方法
ViewController *viewCtlOBJ = [ViewController new];
context[@"viewCtlOBJ"] = viewCtlOBJ;
NSString *jsStr1=[NSString stringWithFormat:@"viewCtlOBJ.closeProgressDialog()"];
[context evaluateScript:jsStr1];
2、js这边调用oc方法
function closeProgressDialog(){
viewCtlOBJ.closeProgressDialog();
}
(三)、使用WebViewJavascriptBridge进行oc和js的交互
备注:兼容iOS7以下版本,我最终使用的这个方法,解决掉js代码崩溃的问题。这个类库是异步执行的,优点:调用oc和js代码优雅,传值和回调方便
1、先导入WebViewJavascriptBridge包,可参考上一篇文章导入。
#import "WebViewJavascriptBridge.h"
@propertyWebViewJavascriptBridge* bridge;
2、OC原生注册方法,实现方法
[WebViewJavascriptBridgeenableLogging];
_bridge = [WebViewJavascriptBridgebridgeForWebView:homeWebView];
[_bridgesetWebViewDelegate:self];
/***
/js调用oc
/@param registerHandler 要注册的事件名称(这里我们为showProgressDialogPhone)
/@param handel 回调block函数 当后台触发这个事件的时候会执行block里面的代码
***/
[_bridgeregisterHandler:@"showProgressDialogPhone"handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"显示加载");
[self showProgressDialog];
responseCallback(@"Response 显示加载");
}];
3、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)
}
setupWebViewJavascriptBridge(function(bridge) {
bridge.callHandler('showProgressDialogPhone', function(response) {
alert(response);
})
});
-----------------------------------------------------------------------------------------
//oc调用js代码
bridge.registerHandler('testJavascriptHandler', function(data, responseCallback) {
log('ObjC called testJavascriptHandler with', data)
var responseData = { 'Javascript Says':'Right back atcha!' }
responseCallback(responseData)
})
//需要传参数,不需要从后台返回执行结果
/***
@param callHandler 商定的事件名称,用来调用网页里面相应的事件实现
@param data id类型,相当于我们函数中的参数,向网页传递函数执行需要的参数
***/
// [_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }];
--------------------------------------------------------------------------------------