在開發中涉及到網頁與iOS原生交互,于是就想到了WebViewJavascriptBridge 這個開源庫。經過最近幾天的研究和了解算是熟悉了它的使用和大致的處理過程。以此記錄作為自己學習總結習慣的開始,也便于不熟悉它的人能快速使用它。
內容包括三個部分。
-
WebViewJavascriptBridge基本使用
-
OC中調用JS方法分析
-
JS中調用OC方法分析
<p>
1、WebViewJavascriptBridge基本使用:
導入工程包含文件如下(圖1):
其支持UIWebView 和 WKWebView,我用的是UIWebView,測試文件** test.html 。
** oc端的操作
首先添加頭文件#import <WebViewJavascriptBridge.h>
//初始化_webBridge對象
_webBridge =[WebViewJavascriptBridge bridgeForWebView:_webview];
[_webBridge setWebViewDelegate:self];
js和iOS方法相互調用之前需要先注冊,如js要調用oc中的方法 * objc_fun1 *,在oc文件中操作如下
//注冊方法供js處調用
[_webBridge registerHandler:@"objc_fun1" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"rec data from js :%@",data);
responseCallback(@"i am from objc!");
}];
//objc_fun1:注冊方法的名稱供js端調用
//handler:具體的方法操作,參數data — js調用時傳遞的參數 ,responseCallback—js 回調操作。
//調用js中的方法
[_webBridge callHandler:@"js_fun1" data:@{@"key":@"hello js"} responseCallback:^(id responseData) {
NSLog(@"from js :%@",responseData);
}];
js端的操作
相關操作基本固定,在 test.html 中,方法 function setupWebViewJavascriptBridge(callback){}的定義不需要改動,我們只是在方法的調用時,在callback 中加入自己的操作。這里注冊oc 需要調用的方法,或者調用oc已注冊過的方法
setupWebViewJavascriptBridge(function(bridge) {
//register functin
bridge.registerHandler('js_fun1', function(data, responseCallback) {
console.log("JS Echo called with:", data)
responseCallback(data)
})
// add button
var btn = document.getElementById('divid1').appendChild(document.createElement('button'))
btn.innerHTML = "callOCFunction"
btn.style="background-color:red;text-align:center"
btn.onclick = function(e){
e.preventDefault()
bridge.callHandler('objc_fun1', {'key':'hello oc,I from JS'}, function responseCallback(responseData) {
var e =document.getElementById('result')
e.innerHTML = "oc response: " + responseData;
})
}
})
//html部分
<body>
<p>this is webviewJavascriptBridge demo</p>
<div>
<p id='result'></p>
</div>
<div style = "background-color:blue;text-align:center;" id = 'divid1' height:40px></div>
</body>
在此注冊了方法中js_fun1可供oc處調用,添加了測試按鈕callOCFunction,點擊通過bridge.callHandler() 調用oc端的方法objc_fun1,返回的結果在頁面上顯示。運行程序后點擊按鈕達到了預期結果,到這里算是完成了基本實用。
2、OC中調用JS方法分析:
WebViewJavascriptBridge中js與oc的交互主要通過- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
url攔截然后對url分析進行js代碼注入,最終實現js與oc的方法相互調用。<p>
首次加載test.html時發起一次請求操作,
url = 'wvjbscheme://__BRIDGE_LOADED__',攔截到該url,通過- >>(void)injectJavascriptFile 方法進行js注入, NSString *js = WebViewJavascriptBridge_js();此js代碼在#import "WebViewJavascriptBridge_JS.h"中,對js中>WebViewJavascriptBridge對象方法和變量進行初始化 主要方法如下:
function registerHandler(handlerName, handler);//注冊方法
function callHandler(handlerName, data, responseCallback);//調用方法
function _doSend(message, responseCallback);
function _fetchQueue();
function _dispatchMessageFromObjC(messageJSON);
function _handleMessageFromObjC(messageJSON);
<p>
OC中調用JS方法順序
1.首先調用方法 - (void)callHandler:(NSString *)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback
參數data,參數形式js端書寫語法。
參數responseCallback,最后的回調操作。
2.- (void)sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName
把發送的數據封裝在一個字典中,如果有responseCallback同時生成一個回調id(objc_cb_1形式的字符串)。
3.- (void)_queueMessage:(WVJBMessage*)message
4.- (void)_dispatchMessage:(WVJBMessage*)message
把消息對象轉化為json字符串,添加字符格式化的處理-> messageJSON,
獲取js代碼字符串
NSString* javascriptCommand = [NSString stringWithFormat:@"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON];
執行js代碼
[self _evaluateJavascript:javascriptCommand];
js中依次調用
function _handleMessageFromObjC(messageJSON) function _dispatchMessageFromObjC(messageJSON)執行js中方法操作
方法結束后,如果此時的oc方法有回調操作->通過function _doSend(message, responseCallback)
再次發起url請求。然后操作回到oc端。
<p>
oc中攔截url請求,分析請求類型為WVJB_QUEUE_MESSAGE調用方法5
5.- (void)flushMessageQueue:(NSString *)messageQueueString
根據js傳入的參數獲取 回調id 'responseId'取出oc方法的回調代碼塊執行,然后在self.responseCallbacks移除已執行的操作。
NSString* responseId = message[@"responseId"];
if (responseId) {
WVJBResponseCallback responseCallback = _responseCallbacks[responseId];
responseCallback(message[@"responseData"]);
[self.responseCallbacks removeObjectForKey:responseId];
}
至此,oc調用js方法執行結束。
3、JS中調用OC方法分析:
依次調用方法順序
JS中的方法操作
在文件#import "WebViewJavascriptBridge_JS.h"中定義的方法
1.function callHandler(handlerName, data, responseCallback);
2.function _doSend(message, responseCallback) 在這個方法中生成回調的id,并保存js端的回調操作,然后發起一次請求回到OC端操作。
oc中攔截url請求,分析請求類型為WVJB_QUEUE_MESSAGE調用方法3
3.- (void)flushMessageQueue:(NSString *)messageQueueString
主要操作代碼如下:
{
WVJBResponseCallback responseCallback = NULL;
NSString* callbackId = message[@"callbackId"];
if (callbackId) {
responseCallback = ^(id responseData) {
if (responseData == nil) {
responseData = [NSNull null];
}
WVJBMessage* msg = @{ @"responseId":callbackId, @"responseData":responseData };
[self _queueMessage:msg];
};
} else {
responseCallback = ^(id ignoreResponseData) {
// Do nothing
};
}
WVJBHandler handler = self.messageHandlers[message[@"handlerName"]];
if (!handler) {
NSLog(@"WVJBNoHandlerException, No handler for message from JS: %@", message);
continue;
}
handler(message[@"data"], responseCallback);
}
根據傳遞過來的方法名,參數,和回調調用oc方法handler(message[@"data"], responseCallback);
如果有回調responseCallback,oc方法執行完后調用[self _queueMessage:msg];
然后操作同OC中調用JS方法順序中步驟3、4又回到JS端執行
function _dispatchMessageFromObjC(messageJSON) {
setTimeout(function _timeoutDispatchMessageFromObjC() {
var message = JSON.parse(messageJSON);
var messageHandler;
var responseCallback;
if (message.responseId) {
responseCallback = responseCallbacks[message.responseId];
if (!responseCallback) {
return;
}
responseCallback(message.responseData);
delete responseCallbacks[message.responseId];
}
根據message.responseId 找到原來保存的回調操作、執行完畢后,刪除該id的操作,至此JS中調用OC方法的操作流程結束。
總結:通過WebViewJavascriptBridge來實現JS、OC的交互,主要通過在OC端進行請求攔截,根據url的類型判斷不同的操作,然后在通過js注入和執行來完成方法的調用,所以每次的事件可能會在OC和JS間多次來回切換。
以上為使用WebViewJavascriptBridge的操作和分析,若理解有不對的地方謝謝指出。