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注册方法中声明
/**
*
* bridge.registerHandler("messageName", function(params, responseCallback) {
* if (responseCallback) {
* // Web端给Native的结果回调
* responseCallback(responseData);
* }
* });
*/
handler(message.data, responseCallback);
} catch (exception) {
if (typeof console != 'undefined') {
}
}
}
});
}
native关键方法
registerHandler方法用于注册Web调用Native的方法
/**
* register handler,so that javascript can call it
*
* @param handlerName 方法名
* @param handler 消息处理类
*/
public void registerHandler(String handlerName, BridgeHandler handler) {
if (handler != null) {
messageHandlers.put(handlerName, handler);
}
}
callHandler方法,用于Native调用Web端方法
/**
* native调用web方法
*
* @param messageName:方法名
* @param data 方法参数
* @param callBack 结果回调
*/
public void callHandler(String messageName, String data, JsCallBack callBack) {
Log.e("调用链路: ",TAG+" callHandler "+messageName+"=="+data);
// 发送消息给web端
doSend(messageName, data, callBack);
}
doSend方法:封装处理Native调用Web端的消息信息
/**
* 发送消息给Web端
* @param messageName 方法名
* @param data 方法参数
* @param responseCallback 结果回调
*/
private void doSend(String messageName, String data, JsCallBack responseCallback) {
Log.e("调用链路: ",TAG+" doSend "+messageName+"=="+data);
// 创建js交互的信息对象
JSMessage m = new JSMessage();
// 设置消息参数
if (!TextUtils.isEmpty(data)) {
m.setParams(data);
}
// 设置消息回调对象
if (responseCallback != null) {
String callbackStr = String.format(JsBridgeUtil.CALLBACK_ID_FORMAT, ++uniqueId + (JsBridgeUtil.UNDERLINE_STR + SystemClock.currentThreadTimeMillis()));
responseCallbacks.put(callbackStr, responseCallback);
m.setCallbackId(callbackStr);
}
// 设置方法名
if (!TextUtils.isEmpty(messageName)) {
m.setMessageName(messageName);
}
Log.e("调用链路: ",TAG+" doSend messsge"+m.toJson());
// 处理消息
queueMessage(m);
}
queueMessage方法:用于保存或分发js交互的消息
/**
* 发送消息给Web端
* @param m js交互的信息
*/
private void queueMessage(JSMessage m) {
// 页面加载完成时会清空消息队列,因此当重新初始化的时候,会把当前页面的js交互消息进行保存
// 保pageMessage存页面的所有js交互信息;注意点:该集合只保存当前页面的交互数据,页面切换的时候需要手动置空,防止存在一个页面出现多次注册,多次接收的情况
if (pageMessage != null) {
pageMessage.add(m);
} else {
// 分发处理js交互的信息
dispatchMessage(m);
}
}
dispatchMessage方法
/**
* 分发处理Native发送给Web端的消息
* @param m js交互的信息
*/
void dispatchMessage(JSMessage m) {
String messageJson = m.toJson();
// json字符串的转义特殊字符
messageJson = messageJson.replaceAll("(\\\\)([^utrn])", "\\\\\\\\$1$2");
messageJson = messageJson.replaceAll("(?<=[^\\\\])(\")", "\\\\\"");
// JS_HANDLE_MESSAGE_FROM_JAVA:javascript:WebViewJavascriptBridge._handleMessageFromNative('%s');调用js中的_handleMessageFromNative方法
String javascriptCommand = String.format(JsBridgeUtil.JS_HANDLE_MESSAGE_FROM_JAVA, messageJson);
Log.e("调用链路: ",TAG+" dispatchMessage "+javascriptCommand);
if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
this.loadUrl(javascriptCommand);
}
}
shouldOverrideUrlLoading 方法:用于处理拦截web端发送过来的消息
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
try {
// url进行UTF-8编码
url = URLDecoder.decode(url, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Log.e("调用链路: ",TAG+" shouldOverrideUrlLoading url="+url);
// RETURN_DATA_SCHAME:ebanma://return/ 代表了Native调用web端刷新消息队列是取出的消息信息,及刷新消息队列返回的消息结果
if (url.startsWith(JsBridgeUtil.RETURN_DATA_SCHAME)) {
// 处理Web侧返回的消息结果
webView.handlerReturnData(url);
return true;
// OVERRIDE_SCHEMA:ebanma://__QUEUE_MESSAGE__/ 代表Web侧主动通知Native去刷新消息队列
} else if (url.startsWith(JsBridgeUtil.OVERRIDE_SCHEMA)) {
// 刷新消息队列
webView.flushMessageQueue();
return true;
} else {
// 此处为jsbridge的二次优化处理,判断当前url是否为web链接,还是Apk的schame跳转链接,
if (urlCanLoad(url)) {
return super.shouldOverrideUrlLoading(view, url);
} else {
// Web侧发送启动Apk的schame链接,通知Native去启动Apk
startThirdpartyApp(url);
return true;
}
}
}
handlerReturnData 方法:用于处理Web侧发送过来的消息结果
public void handlerReturnData(String url) {
//解析url获取回调方法名
String functionName = JsBridgeUtil.getFunctionFromReturnUrl(url);
// 根据方法名从 responseCallbacks中取出回调对象,该回调对象在刷新消息队列的时进行保存
JsCallBack f = responseCallbacks.get(functionName);
// 解析url获取回调结果
String data = JsBridgeUtil.getDataFromReturnUrl(url);
//
if (f != null) {
// 回调flushMessageQueue中的callBack回调
f.callBack(data);
// 移除已处理的回调
responseCallbacks.remove(functionName);
return;
}
}
flushMessageQueue 方法
void flushMessageQueue() {
Log.e("调用链路: ",TAG+" flushMessageQueue ");
if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
Log.e("调用链路: ",TAG+" flushMessageQueue ="+JsBridgeUtil.JS_FETCH_QUEUE_FROM_JAVA);
// javascript:WebViewJavascriptBridge._fetchQueue();执行js中的刷新消息队列的方法
loadUrl(JsBridgeUtil.JS_FETCH_QUEUE_FROM_JAVA, new JsCallBack<String>() {
// 刷新js中的消息队列并获取返回结果,具体执行该方法实在在handlerReturnData
@Override
public void callBack(String data) {
Log.e("调用链路: ",TAG+" flushMessageQueue callBack="+data);
// deserializeMessage
List<JSMessage> list = null;
try {
// 消息结果转换
list = JSMessage.toArrayList(data);
} catch (Exception e) {
e.printStackTrace();
return;
}
if (list == null || list.size() == 0) {
return;
}
// 循环遍历消息
for (int i = 0; i < list.size(); i++) {
JSMessage m = list.get(i);
String responseId = m.getResponseId();
// 根据消息结果中是否包含reponseId区分是Native调用Web给出的结果还是Web调用Native的消息
if (!TextUtils.isEmpty(responseId)) {//Native调用Web给出的结果
// 取出Native调用Web给出的结果回调,该回调实在调用loadUrl方法中进行的保存
JsCallBack function = responseCallbacks.get(responseId);
String responseData = m.getResponseData();
function.callBack(responseData);
responseCallbacks.remove(responseId);
Log.e("调用链路: ",TAG+" flushMessageQueue callBack="+responseData);
} else {//Web调用Native的消息
JsCallBack responseFunction = null;
// if had callbackId
final String callbackId = m.getCallbackId();
if (!TextUtils.isEmpty(callbackId)) {
responseFunction = new JsCallBack<String>() {
@Override
public void callBack(String data) {
}
};
} else {
responseFunction = new JsCallBack<String>() {
@Override
public void callBack(String data) {
// do nothing
}
};
}
IBridgeHandler handler;
if (!TextUtils.isEmpty(m.getMessageName())) {
if (!TextUtils.isEmpty(m.getMessageName())) {
// 取出处理Web调用Native方法的处理函数,其在发送消息函数doSend中进行的保存
handler = messageHandlers.get(m.getMessageName());
if (handler == null) {
handler = defaultHandler;
}
if (handler != null) {
// 处理Web调用Native的方法
handler.handler(m.getMessageName(), m.getParams(), responseFunction);
}
}
}else{
responseFunction.callBack("Web单纯的通知Native时,返回的数据");
}
}
}
}
});
}
}
loadUrl方法:执行js方法,并保存js交互方法的结果回调
public void loadUrl(String jsUrl, JsCallBack returnCallback) {
this.loadUrl(jsUrl);
// 保存Native调用Web时的回调对象
responseCallbacks.put(JsBridgeUtil.parseFunctionName(jsUrl), returnCallback);
}
native中的responseCallbacks常量:保存Native调用Web时的回调对象,在doSend发送消息时保存,在处理结果返回时进行执行回调函数,并移除
native中的messageHandlers常量:保存Web调用Native的处理对象,其在Native注册函数时进行保存,在获取刷新消息队列信息的时候进行取出,并执行消息处理
js交互流程
- Native调用Web流程说明
- Web调用Native流程说明
2丶JsBridge二次开发
2.1丶背景说明
- 针对native侧处理Web调用Native的消息处理类需重复定义,并执行其相关方法;无统一处理,可在任意类中处理,维护较难,可读性差
- 原jsBridge不能和原生的JavaScriptInterface交互方式兼容;
- 原jsBridge交互时,Web与Native进行了四次通信,不仅浪费资源同样耗时,希望能够只交互两次,及发送消息,接收结果
2.2丶二次开发修改点:
-
修改BridgeHandler的handler方法,新增messageName参数,用于消息分发时的判断处理
/** * jsbrdige交互的能力分发 * * @param name 方法名 * @param data 方法参数 * @param function 结果回调 */ void handler(String messageName, String data, JsCallBack function);
-
BridgeHandler的handler处理消息方法中进行消息统一执行处理
/** * js交互的方法分发 * 消息分发的处理类{@link AbstractBridgeMsgDispatch} * @param name 方法名 * @param data 方法参数 * @param function 结果回调 */ @Override public void handler(String name, String data, JsCallBack function) { Log.e("调用链路: ",TAG+" handler data="+data+" name= "+name); mBridgeHandler.handleMessage(name, data, function); }
-
AbstractBridgeMsgDispatch中统一进行消息分发,同时支持同步/异步执行
/** * 统一分发 * * @param messageName 消息名 * @param params 参数 * @param callback 方法回调 * @return 执行结果 */ public String handleMessage(final String messageName, final String params, final JsCallBack callback) { if (callback == null) { return execNative(messageName, params); } else { TaskExecutor.executeTask(new Runnable() { @Override public void run() { TaskExecutor.executeTask(() -> { String response = execNative(messageName, params, callback); TaskExecutor.runTaskOnUiThread(new Runnable() { @Override public void run() { try { JSONObject jsonObject = new JSONObject(response); Object responseData = jsonObject.opt("data"); // BaseAbilityHelper中每个case都需要给result赋值, // 除当前case为执行时回调为异步,result无需赋值,但是需要在当前的case中执行callback.onCallBack(response) if (responseData!=null){ if (response.contains("data")){ callback.callBack(response); } } } catch (JSONException e) { e.printStackTrace(); } } }); }); } }); return null; } }
-
消息的统一处理类BaseAbilityhelper
/** * 基础能力通用处理类 * 添加@JavascriptInterface,兼容JavascriptInterface交互方式 * @param messageName 方法名 * @param params 方法参数 * @param callback 结果回调 * @return 结果返回 */ @Keep @JavascriptInterface @Override public String execNative(String messageName, String params, JsCallBack callback) { String result = null; try { switch (messageName) { case MessageAction.h5_call_native_test: result = "h5_call_native_test_result"; break; default: return getUnSupportResponse(messageName); } } catch (Exception e) { return getErrorResponse(e.getMessage()); } return getSuccessResponse(result); }
-
修改jsBridge.js交互逻辑
修改jsBridge.js文件
//notation: js file can only use this kind of comments //since comments will cause error when use in webview.loadurl, //comments will be remove by java use regexp (function() { if (window.WebViewJavascriptBridge) { return; } var messagingIframe; var receiveMessageQueue = []; // 当前页面的js交互的处理类,通过messageName进行保存和获取 var messageHandlers = {}; // schame 协议的协议 var CUSTOM_PROTOCOL_SCHEME = 'ebanma'; var H5_CALL_NATIVE_MSG = 'h5CallNativeMsg/'; var responseCallbacks = {}; var uniqueId = 1; function _createQueueReadyIframe(doc) { messagingIframe = doc.createElement('iframe'); messagingIframe.style.display = 'none'; doc.documentElement.appendChild(messagingIframe); } //set default messageHandler function init(messageHandler) { if (WebViewJavascriptBridge._messageHandler) { throw new Error('WebViewJavascriptBridge.init called twice'); } WebViewJavascriptBridge._messageHandler = messageHandler; var receivedMessages = receiveMessageQueue; receiveMessageQueue = null; for (var i = 0; i < receivedMessages.length; i++) { _handleNativeCallWebMessage(receivedMessages[i]); } } function send(data, responseCallback) { _callNative({ data: data }, responseCallback); } // 注册native调用Web的方法 function registerHandler(messageName, handler) { console.log("调用链路: "+" registerHandler messageName="+messageName); messageHandlers[messageName] = handler; } function callHandler(messageName, data, responseCallback) { _callNative({ messageName: messageName, data: data }, responseCallback); } function _callNative(message,responseCallback){ if (responseCallback) { var callbackId = 'H5CallNative_cb_' + (uniqueId++) + '_' + new Date().getTime(); responseCallbacks[callbackId] = responseCallback; message.callbackId = callbackId; } messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + H5_CALL_NATIVE_MSG+JSON.stringify(message); } function _nativeCallH5Msg(messageJSON){ console.log("调用链路: "+" _nativeCallH5Msg messageJSON="+JSON.stringify(messageJSON)); console.log("调用链路: "+" _nativeCallH5Msg messageJSON="+(receiveMessageQueue && receiveMessageQueue.length > 0)); if (receiveMessageQueue && receiveMessageQueue.length > 0) { receiveMessageQueue.push(messageJSON); } else { _handleNativeCallWebMessage(messageJSON); } } function _h5CallNativeResult(messageJSON){ setTimeout(function() { console.log("调用链路: "+" _h5CallNativeResult message="+JSON.stringify(messageJSON)); var message = JSON.parse(messageJSON); if (message.responseId) { responseCallback = responseCallbacks[message.responseId]; if (!responseCallback) { return; } console.log("调用链路: "+" _h5CallNativeResult message.responseData="+message.responseData); responseCallback(message.responseData); delete responseCallbacks[message.responseId]; } }); } function _handleNativeCallWebMessage(messageJSON){ setTimeout(function() { console.log("调用链路: "+" _handleNativeCallWebMessage messageJSON="+JSON.stringify(messageJSON)); var message = JSON.parse(messageJSON); if (message.callbackId) { var callbackResponseId = message.callbackId; var messageName = message.messageName; responseCallback = function(responseData) { console.log("调用链路: "+" _handleNativeCallWebMessage responseCallback="+responseData); _nativeCallH5MsgResult({ messageName: messageName, responseId: callbackResponseId, responseData: responseData }); }; } var handler = WebViewJavascriptBridge._messageHandler; if (message.messageName) { handler = messageHandlers[message.messageName]; } //查找指定handler try { handler(message.data, responseCallback); } catch (exception) { if (typeof console != 'undefined') {} } }); } function _nativeCallH5MsgResult(message){ messageQueueString = JSON.stringify(message); console.log("调用链路: "+" _nativeCallH5MsgResult messageQueueString="+messageQueueString); //android can't read directly the return data, so we can reload iframe src to communicate with java messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://nativeCallH5MsgResult/' + encodeURIComponent(messageQueueString); } var WebViewJavascriptBridge = window.WebViewJavascriptBridge = { init: init, send: send, registerHandler: registerHandler, callHandler: callHandler, _nativeCallH5Msg: _nativeCallH5Msg, _h5CallNativeResult: _h5CallNativeResult, }; var doc = document; _createQueueReadyIframe(doc); var readyEvent = doc.createEvent('Events'); readyEvent.initEvent('WebViewJavascriptBridgeReady'); readyEvent.bridge = WebViewJavascriptBridge; doc.dispatchEvent(readyEvent); })();
修改WebViewClient中url拦截方法的处理逻辑,仅保留Web调用Native方法以及Web回调Native结果的
@Override public boolean shouldOverrideUrlLoading(WebView view, String url) { try { url = URLDecoder.decode(url, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } Log.e("调用链路: ",TAG+" shouldOverrideUrlLoading url="+url); if (url.startsWith(JsBridgeUtil.NATIVE_CALL_H5_RESULT)) { webView.handlerNativeCallH5Result(url); return true; }else if (url.startsWith(JsBridgeUtil.H5_CALL_NATIVE_MSG)) { webView.handlerH5CallNativeMsg(url); return true; }else { if (urlCanLoad(url)) { return super.shouldOverrideUrlLoading(view, url); } else { startThirdpartyApp(url); return true; } } }
修改Native调用web方法:直接发送请求信息通知到Web侧
void reallCallWeb(JSMessage m) { String messageJson = m.toJson(); //escape special characters for json string messageJson = messageJson.replaceAll("(\\\\)([^utrn])", "\\\\\\\\$1$2"); messageJson = messageJson.replaceAll("(?<=[^\\\\])(\")", "\\\\\""); String javascriptCommand = String.format(JsBridgeUtil.NATIVE_CALL_H5_HANDLE_MESSSAGE, messageJson); Log.e("调用链路: ", TAG + " reallCallWeb " + javascriptCommand); if (Thread.currentThread() == Looper.getMainLooper().getThread()) { this.loadUrl(javascriptCommand); } }
修改Native接收Web请求的方法:执行结果后,直接返回Web回调结果
public void handlerH5CallNativeMsg(String url) { if (url.startsWith(JsBridgeUtil.H5_CALL_NATIVE_MSG)) { String temp = url.replace(JsBridgeUtil.H5_CALL_NATIVE_MSG, EMPTY_STR); JSMessage m= new Gson().fromJson(temp,JSMessage.class); JsCallBack responseFunction = null; // if had callbackId final String callbackId = m.getCallbackId(); if (!TextUtils.isEmpty(callbackId)) { responseFunction = new JsCallBack<String>() { @Override public void callBack(String data) { JSMessage responseMsg = new JSMessage(); responseMsg.setResponseId(callbackId); responseMsg.setResponseData(data); String messageJson = responseMsg.toJson(); Log.e("调用链路: ", TAG + " handlerH5CallNativeMsg callBack=" + messageJson); //escape special characters for json string messageJson = messageJson.replaceAll("(\\\\)([^utrn])", "\\\\\\\\$1$2"); messageJson = messageJson.replaceAll("(?<=[^\\\\])(\")", "\\\\\""); String javascriptCommand = String.format(JsBridgeUtil.H5_CALL_NATIVE_RESULT, messageJson); Log.e("调用链路: ", TAG + "handlerH5CallNativeMsg callBack " + javascriptCommand); if (Thread.currentThread() == Looper.getMainLooper().getThread()) { loadUrl(javascriptCommand); } } }; } else { responseFunction = new JsCallBack<String>() { @Override public void callBack(String data) { // do nothing } }; } IBridgeHandler handler; if (!TextUtils.isEmpty(m.getMessageName())) { if (!TextUtils.isEmpty(m.getMessageName())) { handler = messageHandlers.get(m.getMessageName()); if (handler == null) { handler = defaultHandler; } if (handler != null) { handler.handler(m.getMessageName(), m.getParams(), responseFunction); } } } else { responseFunction.callBack("Web单纯的通知Native时,返回的数据"); } } }
新js交互流程图
-
Native调用Web流程说明
-
Web调用Native流程说明