Cordova原始碼深入分析-第三講
阿新 • • 發佈:2019-01-10
上一講講解了js端,呼叫到java端的程式碼邏輯
這一講,主要介紹,js->native帶有callback的形式,是如何呼叫回去的
上一篇介紹到了呼叫照相機程式碼的地方,在最後呼叫了:sendPluginResult
這裡呼叫一下:
@Override
public void sendPluginResult(PluginResult cr, String callbackId) {
nativeToJsMessageQueue.addPluginResult(cr, callbackId);
}
NativeToJsMessageQueue.java
public void addPluginResult(PluginResult result, String callbackId) { if (callbackId == null) { LOG.e(LOG_TAG, "Got plugin result with no callbackId", new Throwable()); return; } // Don't send anything if there is no result and there is no need to // clear the callbacks. boolean noResult = result.getStatus() == PluginResult.Status.NO_RESULT.ordinal(); boolean keepCallback = result.getKeepCallback(); if (noResult && keepCallback) { return; } JsMessage message = new JsMessage(result, callbackId); if (FORCE_ENCODE_USING_EVAL) { StringBuilder sb = new StringBuilder(message.calculateEncodedLength() + 50); message.encodeAsJsMessage(sb); message = new JsMessage(sb.toString()); } enqueueMessage(message);//將訊息放到佇列中,裡面含有 }
private void enqueueMessage(JsMessage message) { synchronized (this) { if (activeBridgeMode == null) { LOG.d(LOG_TAG, "Dropping Native->JS message due to disabled bridge"); return; } queue.add(message);//將訊息加入佇列中 if (!paused) { //如果沒有pause則直接執行,有pause的話,下次觸發執行 activeBridgeMode.onNativeToJsMessageAvailable(this);//開始執行 } } }
根據不同的bridge走不同程式碼,這裡先列舉一種情況
@Override
public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {
cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
String js = queue.popAndEncodeAsJs();//取出剛才加入進去的訊息,並且轉換為js
if (js != null) {
engine.loadUrl("javascript:" + js, false);
}
}
});
}
這裡是組裝js的程式碼:
public String popAndEncodeAsJs() {
synchronized (this) {
int length = queue.size();
if (length == 0) {
return null;
}
int totalPayloadLen = 0;
int numMessagesToSend = 0;
for (JsMessage message : queue) {
int messageSize = message.calculateEncodedLength() + 50; // overestimate.
if (numMessagesToSend > 0 && totalPayloadLen + messageSize > MAX_PAYLOAD_SIZE && MAX_PAYLOAD_SIZE > 0) {
break;
}
totalPayloadLen += messageSize;
numMessagesToSend += 1;
}
boolean willSendAllMessages = numMessagesToSend == queue.size();
StringBuilder sb = new StringBuilder(totalPayloadLen + (willSendAllMessages ? 0 : 100));
// Wrap each statement in a try/finally so that if one throws it does
// not affect the next.
for (int i = 0; i < numMessagesToSend; ++i) {
JsMessage message = queue.removeFirst();
if (willSendAllMessages && (i + 1 == numMessagesToSend)) {
message.encodeAsJsMessage(sb);
} else {
sb.append("try{");
message.encodeAsJsMessage(sb);
sb.append("}finally{");
}
}
if (!willSendAllMessages) {
sb.append("window.setTimeout(function(){cordova.require('cordova/plugin/android/polling').pollOnce();},0);");
}
for (int i = willSendAllMessages ? 1 : 0; i < numMessagesToSend; ++i) {
sb.append('}');
}
String ret = sb.toString();
Log.v("XPC","ret="+ret);//ret=cordova.callbackFromNative('Camera1024838304',false,9,["No Image Selected"],false);
return ret;
}
}
看一下encodeAsJsMessage
void encodeAsJsMessage(StringBuilder sb) {
if (pluginResult == null) {
sb.append(jsPayloadOrCallbackId);
} else {
int status = pluginResult.getStatus();
boolean success = (status == PluginResult.Status.OK.ordinal()) || (status == PluginResult.Status.NO_RESULT.ordinal());
sb.append("cordova.callbackFromNative('")
.append(jsPayloadOrCallbackId)
.append("',")
.append(success)
.append(",")
.append(status)
.append(",[");
buildJsMessage(sb);
sb.append("],")
.append(pluginResult.getKeepCallback())
.append(");");
}
}
這樣就調回了js端的cordova.js端
callbackFromNative: function(callbackId, isSuccess, status, args, keepCallback) {
try {
var callback = cordova.callbacks[callbackId];//根據callbackId找到我們之前的函式,這個在上一講中,寫到過,
if (callback) {
if (isSuccess && status == cordova.callbackStatus.OK) {
callback.success && callback.success.apply(null, args);//這裡會直接呼叫camera.js的成功和失敗方法中
} else if (!isSuccess) {
callback.fail && callback.fail.apply(null, args);
}
/*
else
Note, this case is intentionally not caught.
this can happen if isSuccess is true, but callbackStatus is NO_RESULT
which is used to remove a callback from the list without calling the callbacks
typically keepCallback is false in this case
*/
// Clear callback if not expecting any more results
if (!keepCallback) {
delete cordova.callbacks[callbackId];
}
}
}
catch (err) {
var msg = "Error in " + (isSuccess ? "Success" : "Error") + " callbackId: " + callbackId + " : " + err;
console && console.log && console.log(msg);
cordova.fireWindowEvent("cordovacallbackerror", { 'message': msg });
throw err;
}
},
本講結束!!!!下一講java端的外掛系統是如何建立關聯的