一、bridge 初始化
self.bridge = [WebViewJavascriptBridge bridgeForWebView:webView];
這里并沒有注冊 js 的 bridge。而是在 js 第一次調用 native 的時候,才去執行的 bridge 中的 js 方法。去注冊 js 端的 bridge。
二、native 注冊 methods
native 調用 registerHandler
方法,并沒有真的注入方法到 js context 里面,而是存儲到了_base.messageHandlers
這個Dictionary 中。
[self.bridge registerHandler:@"ObjC Echo" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"ObjC Echo called with: %@", data);
responseCallback(data);
}];
- (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler {
_base.messageHandlers[handlerName] = [handler copy];
}
三、注冊 js 端的 bridge
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)
}
在第一個 js 調用 native 方法的時候,window.WebViewJavascriptBridge
是沒有值的,所以下面會調用一個 https://__bridge_loaded__
的鏈接,native 端 bridge 接收到這個鏈接后,才去執行 注入的 js 端 bridge。
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
if (webView != _webView) { return; }
NSURL *url = navigationAction.request.URL;
__strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;
if ([_base isWebViewJavascriptBridgeURL:url]) {
if ([_base isBridgeLoadedURL:url]) {// 判斷是 load bridge的 url
[_base injectJavascriptFile];
} else if ([_base isQueueMessageURL:url]) {// 判斷是 執行方法
[self WKFlushMessageQueue];
} else {
[_base logUnkownMessage:url];
}
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:decisionHandler:)]) {
[_webViewDelegate webView:webView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler];
} else {
decisionHandler(WKNavigationActionPolicyAllow);
}
}