看了这个Github代码 https://github.com/lzyzsd/JsBridge,想起N年前比较火的Hybrid方案,想看看现在跨平台调用实现有什么新的实现方式。代码看下来之后发现确实有点独特之处,这里先把核心的思想抛出,然后在细化Native (Java)如何调JS以及JS如何调Native (Java)。
Native与JS相互调用使用的最核心的思路是:
1、Native通过WebView的loadUrl调用JS的code;
2、JS通过设置URL跳转触发WebViewClient的shouldOverrideUrlLoading通知Native有数据发生;
当然这只是核心思路,实际上还涉及到一些细节,其中比较重要的就是scheme的设计,双方都是通过这个scheme来约定方法和返回数据。可以参考BridgeUtils的YY_RETURN_DATA和YY_FETCH_QUEUE。当然还有方法名的约定;以及交换数据格式的约定(JSON)。
一、Native(Java)调JS
在Native调JS之前,需要现在JS中注册handler,也就是方法名与方法体, 参考Github README:
WebViewJavascriptBridge.registerHandler("functionInJs", function(data, responseCallback) { document.getElementById("show").innerHTML = ("data from Java: = " + data); var responseData = "Javascript Says Right back aka!"; responseCallback(responseData); });
Native调用JS
webView.callHandler("functionInJs", new Gson().toJson(user), new CallBackFunction() { @Override public void onCallBack(String data) { } });
需要传递之前约定的方法名,方法参数(json格式)以及一个JS执行结果返回的callbackFunction。
1、JS注册自己对外开放的接口,用于被Native调用;
2、外部调用BridgeWebView的callHanlder方法调用js接口,传递的参数为约定的方法名,json格式的参数以及一个callback,这个callback用于接收js接口返回的结果;
3、callHandler调用内部的doSend方法,doSend方法中构造一个message,这个message中包含方法名,参数json内容以及一个新构造的callbackId,这个id还用于接收js返回结果的callback的key,保存到map中用于后续查找对应的callback;然后会调用queueMessage进行分发;
4、queueMessage主要是调用dispatchMessage进行处理;
5、dispatchMessage中构造一个url用于进行js调用,这个url是“WebViewJavascriptBridge._handleMessageFromNative('message的json格式');”,
6、通过loadUrl触发js的接口被调用;
7、触发JsBridge中的_handleMessageFromNative被调用;
8、调用_dispatchMessageFromNative进行message消息的处理,
9、_dispatchMessageFromNative中,根据message的json,找到handler name并找到1中注册的handler,然后调用handler处理message中包含的data;在handler执行之前,构造了一个responseCallback,这个responseCallback在handler执行之后会被执行,
_doSend({ responseId: callbackResponseId, responseData: responseData });
10、_doSend中,这个json内容被放进一个queue中留作后用(主要是用于后续被Native请求得到),暂时不会直接返回,这个responseId就是之前传递过来的message中的callbackId;
var callbackResponseId = message.callbackId;
11、通过重定向url,触发BridgeWebViewClient的shouldOverrideUrlLoading;
12、在shouldOverrideUrlLoading中,会根据url的前缀判断调用webview中的哪个方法,这里调用的是flushMessageQueue;
13、flushMessageQueue中做的事情比较绕圈子,它首先构造了一个新的responseCallback,在这个responseCallback中封装了针对之前注册的callback的调用,之后,这个responseCallback作为方法‘return’的value存进map中,用于后续handlerReturnData中被处理;
14、通过loadUrl(‘WebViewJavascriptBridge._fetchQueue();’)触发JsBridge的_fetchQueue;
this.loadUrl(jsUrl); // 添加至 Map<String, CallBackFunction> responseCallbacks.put(BridgeUtil.parseFunctionName(jsUrl), returnCallback);
这里jsUrl就是‘WebViewJavascriptBridge._fetchQueue();’
15、在jsBridge中的_fetchQueue函数中,把10中保存的queue中的json数据转换成json string,作为url的一部分进行跳转
function _fetchQueue() { var messageQueueString = JSON.stringify(sendMessageQueue); sendMessageQueue = []; //android can't read directly the return data, so we can reload iframe src to communicate with java bizMessagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://return/_fetchQueue/' + encodeURIComponent(messageQueueString); }
这会导致BridgeWebViewClient的shouldOverrideUrlLoading被触发;
16、在BridgeWebViewClient的shouldOverrideUrlLoading中,这回根据url前缀,判断需要调用BridgeWebView的
webView.handlerReturnData(url);
17、在BridgeWebView的handlerReturnData中,
void handlerReturnData(String url) { String functionName = BridgeUtil.getFunctionFromReturnUrl(url); CallBackFunction f = responseCallbacks.get(functionName); String data = BridgeUtil.getDataFromReturnUrl(url); if (f != null) { f.onCallBack(data); responseCallbacks.remove(functionName); return; } }
根据url找到对应的方法就是13中的‘return’以及它对应的callbackFunction,也是13中对callbackId对应的callback进行封装的callback,然后提取出15中的json data,回调callback。在onCallBack中,会找到json中的callbackId以及js执行的结果data,然后用callbackid对应的callback调用data完成js执行结果的处理。
至此,从Native调用JS以及处理JS调用返回内容的流程完毕。至于JS调用Native的流程跟这个类似,可以根据源码进行还原。总之还是开头总结的:
Native与JS相互调用使用的最核心的思路是:
1、Native通过WebView的loadUrl调用JS的code;
2、JS通过设置URL跳转触发WebViewClient的shouldOverrideUrlLoading通知Native有数据发生;