看簡書上說一共有六種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" }];
--------------------------------------------------------------------------------------