JsBridge原理以及二次开发
1丶JsBridge原理
1.1丶JS交互的简单使用
-
🏷原生方式
-
Native调用Web:
方式1:Android4.2以前
webView.loadUrl(jsMethod);
方式2:Android4.2以后:新增
webView.evaluateJavascript(jsMethod, new ValueCallback<String>() { @Override public void onReceiveValue(String s) { Log.d(TAG, "nativeCallH5ByPrimary2 onReceiveValue: "+s); } });
两种方式对比:
调用方式 版本支持 是否刷新页面 是否存在回调 是否可获取常量信息 loadUrl Android各版本 是 否 否 evaluateJavascript Android4.2及以上 否 是 是 -
Web调用Native:Native提供JavaScript交互的对象
**方式1:**调用Native挂载在window上的对象进行调用
Native添加JavaScript
webView.addJavascriptInterface(new JSHelper(), "jsHelper");
web调用Native方法
window.jsHelper.webCallNativeFunc();
方式2:Web端调用location.href的方式调用(需要Native进行拦截相应的url进行处理)**
location.href='xxxxx'
方式3:Web端创建iframe标签,通过iframe.src方式调用(需要Native进行拦截相应的url进行处理)**
iframe.src='xxxxx'
三种种方式对比:
调用方式 是否刷新页面 是否存在回调 其他 window.jsHelper 否 具体看Native方法 需Native创建js交互对象,并挂载在window上 location.href 是 否 需要Native进行拦截相应的url进行处理;连续多次调用只执行最后一次 iframe.src 否 否 需要Native进行拦截相应的url进行处理;
-
-
🏷JsBridge
-
Native调用Web
//functionInJs该方法需Web端注册 webView.callHandler("functionInJs", "TEST BRIDGE", new JsCallBack() { @Override public void callBack(String result) { Log.e(TAG, "repsonseData from web, data = : "+result ); } }); //or webView.sendMessage("functionInJs", "TEST BRIDGE", new JsCallBack() { @Override public void callBack(String data) { Log.e(TAG, "repsonseData from web, data = : "+result ); } });
-
Web调用Native
// functionInNative该方法需Native端注册 window.WebViewJavascriptBridge.callHandler( 'functionInNative' , params , function(responseData) { console.log("repsonseData from java, data = " + responseData); } );
-
1.2丶JsBridge交互方式和原生交互方式对比
交互方式 | 调用链路 | 交互方法 | 优点 | 缺点 |
原生交互 | NativeCallH5 | laodurl | 版本支持Android4.2以下,兼容较好 | 1.会刷新页面 2.无返回值 3.js属性值无法获取 |
evaluateJavascript | 支持Web返回值 | 1.返回值是否存在由js方法决定 | ||
H5CallNative | window对象 | 结果同步返回 | 1.需Native声明js交互对象并挂载到Window上 | |
location.href | 调用方便 | 1.无返回值且需要Native针对URL进行拦截处理 2.连续多次调用只执行最后一次 |
||
iframe.src | 独立窗口处理js交互 | 1.无返回值且需要Native针对URL进行拦截处理 | ||
JsBridge交互 | NativeCallH5 | sendMessage | 1.版本兼容良好 2.均存在返回值 3.调用方式简单 |
1.需要Native针对URL进行拦截处理 2.需Web注入jsbridge.js 3.交互方法需接收端进行注册 |
callHandler | ||||
H5CallNative |
1.3丶JsBridge原理
js关键方法
Web端注册方法
// Web端注册方法
bridge.registerHandler("messageName", function(params, responseCallback) {
if (responseCallback) {
// Web端给Native的结果回调
responseCallback(responseData);
}
});
JsBridge.js中的方法
registerHandler方法负责注册native调用Web的方法
// 注册native调用Web的方法
function registerHandler(messageName, handler) {
messageHandlers[messageName] = handler;
}
// 保存web端当前页面的js交互的处理类,通过messageName进行保存和获取
var messageHandlers = {
};
callHandler方法,用于Web调用Native的关键方法,其内部调用了_send方法
function callHandler(messageName, data, responseCallback) {
_doSend({
messageName: messageName,
data: data
}, responseCallback);
}
_doSend 方法用于Web端发送消息给Native侧,同时保存相应的回调对象,回调对象用于后面接收处理Native的回调结果
function _doSend(message, responseCallback) {
console.log("调用链路: "+" _doSend message="+JSON.stringify(message));
// 判断当前的responseCallback对象是否为空,该判断的作用是用于区分是Web端调用Native方法,还是Web主动通知Native去刷新消息队列
if (responseCallback) {
var callbackId = 'H5CallNative_cb_' + (uniqueId++) + '_' + new Date().getTime();
// web保存调用Native方法时的回调对象,最后会在_dispatchMessageFromNative分发处理Native发送过来的消息时取出,并返回
responseCallbacks[callbackId] = responseCallback;
message.callbackId = callbackId;
}
// 保存Web端发送的消息信息
sendMessageQueue.push(message);
// iframe.src主动发送请求通知Native,该uri最终会执行到WebViewCilent中的shouldOverrideUrlLoading方法
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE;
}
_fetchQueue 方法,web侧提供给Native调用的方法,用于刷新消息队列信息,并把消息结果返回给Native
// 提供给native调用,该函数作用:获取sendMessageQueue中的数据返回给native,因为android不能直接获取返回的内容,因此使用url shouldOverrideUrlLoading 的方式返回内容
function _fetchQueue() {
// 取出所有的发送消息的信息内容
var messageQueueString = JSON.stringify(sendMessageQueue);
console.log("调用链路: "+" _fetchQueue messageQueueString="+messageQueueString);
// 置空消息队列
sendMessageQueue = [];
//android无法直接读取返回数据,因此我们可以重新加载iframe src以与java通信
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://return/_fetchQueue/' + encodeURIComponent(messageQueueString);
}
_handleMessageFromNative方法,用于Web侧处理native发送过来的消息
function _handleMessageFromNative(messageJSON) {
console.log("调用链路: "+" _handleMessageFromNative messageJSON="+messageJSON);
console.log("调用链路: "+" _handleMessageFromNative bool="+(receiveMessageQueue && receiveMessageQueue.length > 0));
//页面加载完成时会清空消息队列,因此当重新初始化的时候,会把当前页面的js交互消息进行保存
if (receiveMessageQueue && receiveMessageQueue.length > 0) {
receiveMessageQueue.push(messageJSON);
} else {
// 分发处理Native发送过来的消息
_dispatchMessageFromNative(messageJSON);
}
}
_dispatchMessageFromNative 方法,分发处理Native发送过来的消息
function _dispatchMessageFromNative(messageJSON) {
setTimeout(function() {
var message = JSON.parse(messageJSON);
var responseCallback;
// Web调用native完成后,js获取结果的回调函数,
if (message.responseId) {
// 从responseCallbacks集合中取出结果回调,该回调是在web调用_doSend方法时进行保存的
responseCallback = responseCallbacks[message.responseId];
if (!responseCallback) {
return;
}
responseCallback(message.responseData);
// 从responseCallbacks集合中移除结果回调
delete responseCallbacks[message.responseId];
} else {
// native主动调用Web方法,发送的消息
if (message.callbackId) {
var callbackResponseId = message.callbackId;
responseCallback = function(responseData) {
// 当web处理native发送过来的消息结束后会调用该方法,发送消息给Native侧,通知已经处理好结果
_doSend({
responseId: callbackResponseId,
responseData: responseData
});
};
}
var handler = WebViewJavascriptBridge._messageHandler;
if (message.messageName) {
// 取出处理Native调用web方法的处理函数对象,该对象是在Web端注册方法时进行保存的
handler = messageHandlers[message.messageName];
}
//查找指定handler
try {
// 处理native发送过来的消息.该方法在Web端registerHandler注册方法中声明
/**
*