反馈请联系hertz@hertzwang.com,谢谢
概述
WebViewJavascriptBridge可用于iOS原生(以下简称原生)与JavaScript(以下简称JS)交互,集成和使用参考README.md
Bridge通过WebView初始化后加载网页,html首次加载时新建一个隐藏的iframe,通过设置scr来触发原生URL拦截从而达到注入JS的目的
原生注册方法供JS调用:JS调用时先将方法名和传参缓存(至sendMessageQueue
),再更新iframe.scr
触发原生URL拦截(-webView:decidePolicyForNavigationAction:decisionHandler:
),原生调用JS方法(WebViewJavascriptBridge._fetchQueue();
)获取方法名和传参,解析后从bridge.base.messageHandlers
取出对应的Block
然后执行
JS注册方法供原生调用:原生通过bridge
可直接调用JS方法
文件目录
- WebViewJavascriptBridge:适用于UIWebView的Bridge,操作系统在
MAC_10_9
以上或设备为IPHONE_7_1
及上中,使用WebViewJavascriptBridgeBase
对象做为Bridge - WKWebViewJavascriptBridge:适用于WKWebView的Bridge
- WebViewJavascriptBridgeBase:Bridge的基于组件,用于存储原生注册的方法、封装JS方法的调用等
- WebViewJavascriptBridge_JS:声名的C方法,内部有注入WebView中的JS代码
原生部分
WebViewJavascriptBridge属性初始化
使用方法[WebViewJavascriptBridge bridgeForWebView:webView]
初始化会得到一个实例(以下简称bridge),内部实现如下:
- weak当前webView
- 设置webView.navigationDelegate = self
- 新建
WebViewJavascriptBridgeBase
属性(以下简称bridgeBase)- messageHandlers存储原生注册的方法
注册原生方法-registerHandler:handler:
bridge
调用后会存储在bridgeBase
的messageHandlers
中
原生调用JS方法-callHandler:data:
bridge
调用后bridgeBase
会将方法及参数格式化成WebViewJavascriptBridge._handleMessageFromObjC('%@');
后,调用webView
的-evaluateJavaScript:completionHandler:
这里的WebViewJavascriptBridge
是被注入到WebView
中JS的window属性,代码如下:
window.WebViewJavascriptBridge = {
registerHandler: registerHandler,
callHandler: callHandler,
disableJavscriptAlertBoxSafetyTimeout: disableJavscriptAlertBoxSafetyTimeout,
_fetchQueue: _fetchQueue,
_handleMessageFromObjC: _handleMessageFromObjC,
};
方法_handleMessageFromObjC
直接调用_dispatchMessageFromObjC
来处理JS的方法调用
JS部分
声名setupWebViewJavascriptBridge方法
在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)
}
- WebViewJavascriptBridge:上述中讲到是window的属性,在注入的JS代码中声名,其包含以下属性:
- registerHandler:存储JS注册的方法
- callHandler:调用原生方法(存储调用原生的方法和参数对象至
sendMessageQueue
,更新iframe.scr
触发原生拦截从而调用JS方法从sendMessageQueue
中获取对象,原生解析对象后调用相应的方法) - _fetchQueue:获取
sendMessageQueue
中存储的原生方法名和参数 - _handleMessageFromObjC:直接调用
_dispatchMessageFromObjC
来处理JS的方法调用
- WVJBIframe:隐藏的iframe,通过修改它的src来触发原生拦截
注册JS方法bridge.registerHandler
setupWebViewJavascriptBridge(function(bridge) {
/* Initialize your app here */
bridge.registerHandler('JS Echo', function(data, responseCallback) {
console.log("JS Echo called with:", data)
responseCallback(data)
})
})
JS调用原生方法bridge.callHandler
setupWebViewJavascriptBridge(function(bridge) {
bridge.callHandler('ObjC Echo', {'key':'value'}, function responseCallback(responseData) {
console.log("JS received response:", responseData)
})
})