mirror of
https://github.com/apache/cordova-android.git
synced 2025-01-19 15:12:51 +08:00
CB-7707 Added multipart PluginResult (close #125)
Corresponds to cordova-js commit: a1f866606b3
This commit is contained in:
parent
2dcd50c11b
commit
fbeb379f1b
110
framework/assets/www/cordova.js
vendored
110
framework/assets/www/cordova.js
vendored
@ -1,5 +1,5 @@
|
|||||||
// Platform: android
|
// Platform: android
|
||||||
// 8ca0f3b2b87e0759c5236b91c80f18438544409c
|
// 1fc2526faa6197e1637ecb48ebe0f876f008ba0f
|
||||||
/*
|
/*
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
@ -263,11 +263,7 @@ var cordova = {
|
|||||||
* Called by native code when returning successful result from an action.
|
* Called by native code when returning successful result from an action.
|
||||||
*/
|
*/
|
||||||
callbackSuccess: function(callbackId, args) {
|
callbackSuccess: function(callbackId, args) {
|
||||||
try {
|
cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
|
||||||
cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Error in success callback: " + callbackId + " = "+e);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -276,30 +272,34 @@ var cordova = {
|
|||||||
callbackError: function(callbackId, args) {
|
callbackError: function(callbackId, args) {
|
||||||
// TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
|
// TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
|
||||||
// Derive success from status.
|
// Derive success from status.
|
||||||
try {
|
cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
|
||||||
cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Error in error callback: " + callbackId + " = "+e);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by native code when returning the result from an action.
|
* Called by native code when returning the result from an action.
|
||||||
*/
|
*/
|
||||||
callbackFromNative: function(callbackId, success, status, args, keepCallback) {
|
callbackFromNative: function(callbackId, isSuccess, status, args, keepCallback) {
|
||||||
var callback = cordova.callbacks[callbackId];
|
try {
|
||||||
if (callback) {
|
var callback = cordova.callbacks[callbackId];
|
||||||
if (success && status == cordova.callbackStatus.OK) {
|
if (callback) {
|
||||||
callback.success && callback.success.apply(null, args);
|
if (isSuccess && status == cordova.callbackStatus.OK) {
|
||||||
} else if (!success) {
|
callback.success && callback.success.apply(null, args);
|
||||||
callback.fail && callback.fail.apply(null, args);
|
} else {
|
||||||
}
|
callback.fail && callback.fail.apply(null, args);
|
||||||
|
}
|
||||||
|
|
||||||
// Clear callback if not expecting any more results
|
// Clear callback if not expecting any more results
|
||||||
if (!keepCallback) {
|
if (!keepCallback) {
|
||||||
delete cordova.callbacks[callbackId];
|
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;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
addConstructor: function(func) {
|
addConstructor: function(func) {
|
||||||
channel.onCordovaReady.subscribe(function() {
|
channel.onCordovaReady.subscribe(function() {
|
||||||
@ -1013,6 +1013,42 @@ androidExec.setNativeToJsBridgeMode = function(mode) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function buildPayload(payload, message) {
|
||||||
|
var payloadKind = message.charAt(0);
|
||||||
|
if (payloadKind == 's') {
|
||||||
|
payload.push(message.slice(1));
|
||||||
|
} else if (payloadKind == 't') {
|
||||||
|
payload.push(true);
|
||||||
|
} else if (payloadKind == 'f') {
|
||||||
|
payload.push(false);
|
||||||
|
} else if (payloadKind == 'N') {
|
||||||
|
payload.push(null);
|
||||||
|
} else if (payloadKind == 'n') {
|
||||||
|
payload.push(+message.slice(1));
|
||||||
|
} else if (payloadKind == 'A') {
|
||||||
|
var data = message.slice(1);
|
||||||
|
var bytes = window.atob(data);
|
||||||
|
var arraybuffer = new Uint8Array(bytes.length);
|
||||||
|
for (var i = 0; i < bytes.length; i++) {
|
||||||
|
arraybuffer[i] = bytes.charCodeAt(i);
|
||||||
|
}
|
||||||
|
payload.push(arraybuffer.buffer);
|
||||||
|
} else if (payloadKind == 'S') {
|
||||||
|
payload.push(window.atob(message.slice(1)));
|
||||||
|
} else if (payloadKind == 'M') {
|
||||||
|
var multipartMessages = message.slice(1);
|
||||||
|
while (multipartMessages !== "") {
|
||||||
|
var spaceIdx = multipartMessages.indexOf(' ');
|
||||||
|
var msgLen = +multipartMessages.slice(0, spaceIdx);
|
||||||
|
var multipartMessage = multipartMessages.substr(spaceIdx + 1, msgLen);
|
||||||
|
multipartMessages = multipartMessages.slice(spaceIdx + msgLen + 1);
|
||||||
|
buildPayload(payload, multipartMessage);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
payload.push(JSON.parse(message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Processes a single message, as encoded by NativeToJsMessageQueue.java.
|
// Processes a single message, as encoded by NativeToJsMessageQueue.java.
|
||||||
function processMessage(message) {
|
function processMessage(message) {
|
||||||
try {
|
try {
|
||||||
@ -1026,32 +1062,10 @@ function processMessage(message) {
|
|||||||
var status = +message.slice(2, spaceIdx);
|
var status = +message.slice(2, spaceIdx);
|
||||||
var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
|
var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
|
||||||
var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
|
var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
|
||||||
var payloadKind = message.charAt(nextSpaceIdx + 1);
|
var payloadMessage = message.slice(nextSpaceIdx + 1);
|
||||||
var payload;
|
var payload = [];
|
||||||
if (payloadKind == 's') {
|
buildPayload(payload, payloadMessage);
|
||||||
payload = message.slice(nextSpaceIdx + 2);
|
cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);
|
||||||
} else if (payloadKind == 't') {
|
|
||||||
payload = true;
|
|
||||||
} else if (payloadKind == 'f') {
|
|
||||||
payload = false;
|
|
||||||
} else if (payloadKind == 'N') {
|
|
||||||
payload = null;
|
|
||||||
} else if (payloadKind == 'n') {
|
|
||||||
payload = +message.slice(nextSpaceIdx + 2);
|
|
||||||
} else if (payloadKind == 'A') {
|
|
||||||
var data = message.slice(nextSpaceIdx + 2);
|
|
||||||
var bytes = window.atob(data);
|
|
||||||
var arraybuffer = new Uint8Array(bytes.length);
|
|
||||||
for (var i = 0; i < bytes.length; i++) {
|
|
||||||
arraybuffer[i] = bytes.charCodeAt(i);
|
|
||||||
}
|
|
||||||
payload = arraybuffer.buffer;
|
|
||||||
} else if (payloadKind == 'S') {
|
|
||||||
payload = window.atob(message.slice(nextSpaceIdx + 2));
|
|
||||||
} else {
|
|
||||||
payload = JSON.parse(message.slice(nextSpaceIdx + 1));
|
|
||||||
}
|
|
||||||
cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback);
|
|
||||||
} else {
|
} else {
|
||||||
console.log("processMessage failed: invalid message: " + JSON.stringify(message));
|
console.log("processMessage failed: invalid message: " + JSON.stringify(message));
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ public class NativeToJsMessageQueue {
|
|||||||
|
|
||||||
// Set this to true to force plugin results to be encoding as
|
// Set this to true to force plugin results to be encoding as
|
||||||
// JS instead of the custom format (useful for benchmarking).
|
// JS instead of the custom format (useful for benchmarking).
|
||||||
|
// Doesn't work for multipart messages.
|
||||||
private static final boolean FORCE_ENCODE_USING_EVAL = false;
|
private static final boolean FORCE_ENCODE_USING_EVAL = false;
|
||||||
|
|
||||||
// Disable sending back native->JS messages during an exec() when the active
|
// Disable sending back native->JS messages during an exec() when the active
|
||||||
@ -419,53 +420,43 @@ public class NativeToJsMessageQueue {
|
|||||||
this.pluginResult = pluginResult;
|
this.pluginResult = pluginResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int calculateEncodedLengthHelper(PluginResult pluginResult) {
|
||||||
|
switch (pluginResult.getMessageType()) {
|
||||||
|
case PluginResult.MESSAGE_TYPE_BOOLEAN: // f or t
|
||||||
|
case PluginResult.MESSAGE_TYPE_NULL: // N
|
||||||
|
return 1;
|
||||||
|
case PluginResult.MESSAGE_TYPE_NUMBER: // n
|
||||||
|
return 1 + pluginResult.getMessage().length();
|
||||||
|
case PluginResult.MESSAGE_TYPE_STRING: // s
|
||||||
|
return 1 + pluginResult.getStrMessage().length();
|
||||||
|
case PluginResult.MESSAGE_TYPE_BINARYSTRING:
|
||||||
|
return 1 + pluginResult.getMessage().length();
|
||||||
|
case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
|
||||||
|
return 1 + pluginResult.getMessage().length();
|
||||||
|
case PluginResult.MESSAGE_TYPE_MULTIPART:
|
||||||
|
int ret = 1;
|
||||||
|
for (int i = 0; i < pluginResult.getMultipartMessagesSize(); i++) {
|
||||||
|
int length = calculateEncodedLengthHelper(pluginResult.getMultipartMessage(i));
|
||||||
|
int argLength = String.valueOf(length).length();
|
||||||
|
ret += argLength + 1 + length;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
case PluginResult.MESSAGE_TYPE_JSON:
|
||||||
|
default:
|
||||||
|
return pluginResult.getMessage().length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int calculateEncodedLength() {
|
int calculateEncodedLength() {
|
||||||
if (pluginResult == null) {
|
if (pluginResult == null) {
|
||||||
return jsPayloadOrCallbackId.length() + 1;
|
return jsPayloadOrCallbackId.length() + 1;
|
||||||
}
|
}
|
||||||
int statusLen = String.valueOf(pluginResult.getStatus()).length();
|
int statusLen = String.valueOf(pluginResult.getStatus()).length();
|
||||||
int ret = 2 + statusLen + 1 + jsPayloadOrCallbackId.length() + 1;
|
int ret = 2 + statusLen + 1 + jsPayloadOrCallbackId.length() + 1;
|
||||||
switch (pluginResult.getMessageType()) {
|
return ret + calculateEncodedLengthHelper(pluginResult);
|
||||||
case PluginResult.MESSAGE_TYPE_BOOLEAN: // f or t
|
|
||||||
case PluginResult.MESSAGE_TYPE_NULL: // N
|
|
||||||
ret += 1;
|
|
||||||
break;
|
|
||||||
case PluginResult.MESSAGE_TYPE_NUMBER: // n
|
|
||||||
ret += 1 + pluginResult.getMessage().length();
|
|
||||||
break;
|
|
||||||
case PluginResult.MESSAGE_TYPE_STRING: // s
|
|
||||||
ret += 1 + pluginResult.getStrMessage().length();
|
|
||||||
break;
|
|
||||||
case PluginResult.MESSAGE_TYPE_BINARYSTRING:
|
|
||||||
ret += 1 + pluginResult.getMessage().length();
|
|
||||||
break;
|
|
||||||
case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
|
|
||||||
ret += 1 + pluginResult.getMessage().length();
|
|
||||||
break;
|
|
||||||
case PluginResult.MESSAGE_TYPE_JSON:
|
|
||||||
default:
|
|
||||||
ret += pluginResult.getMessage().length();
|
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void encodeAsMessage(StringBuilder sb) {
|
static void encodeAsMessageHelper(StringBuilder sb, PluginResult pluginResult) {
|
||||||
if (pluginResult == null) {
|
|
||||||
sb.append('J')
|
|
||||||
.append(jsPayloadOrCallbackId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int status = pluginResult.getStatus();
|
|
||||||
boolean noResult = status == PluginResult.Status.NO_RESULT.ordinal();
|
|
||||||
boolean resultOk = status == PluginResult.Status.OK.ordinal();
|
|
||||||
boolean keepCallback = pluginResult.getKeepCallback();
|
|
||||||
|
|
||||||
sb.append((noResult || resultOk) ? 'S' : 'F')
|
|
||||||
.append(keepCallback ? '1' : '0')
|
|
||||||
.append(status)
|
|
||||||
.append(' ')
|
|
||||||
.append(jsPayloadOrCallbackId)
|
|
||||||
.append(' ');
|
|
||||||
switch (pluginResult.getMessageType()) {
|
switch (pluginResult.getMessageType()) {
|
||||||
case PluginResult.MESSAGE_TYPE_BOOLEAN:
|
case PluginResult.MESSAGE_TYPE_BOOLEAN:
|
||||||
sb.append(pluginResult.getMessage().charAt(0)); // t or f.
|
sb.append(pluginResult.getMessage().charAt(0)); // t or f.
|
||||||
@ -489,12 +480,42 @@ public class NativeToJsMessageQueue {
|
|||||||
sb.append('A');
|
sb.append('A');
|
||||||
sb.append(pluginResult.getMessage());
|
sb.append(pluginResult.getMessage());
|
||||||
break;
|
break;
|
||||||
|
case PluginResult.MESSAGE_TYPE_MULTIPART:
|
||||||
|
sb.append('M');
|
||||||
|
for (int i = 0; i < pluginResult.getMultipartMessagesSize(); i++) {
|
||||||
|
PluginResult multipartMessage = pluginResult.getMultipartMessage(i);
|
||||||
|
sb.append(String.valueOf(calculateEncodedLengthHelper(multipartMessage)));
|
||||||
|
sb.append(' ');
|
||||||
|
encodeAsMessageHelper(sb, multipartMessage);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case PluginResult.MESSAGE_TYPE_JSON:
|
case PluginResult.MESSAGE_TYPE_JSON:
|
||||||
default:
|
default:
|
||||||
sb.append(pluginResult.getMessage()); // [ or {
|
sb.append(pluginResult.getMessage()); // [ or {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void encodeAsMessage(StringBuilder sb) {
|
||||||
|
if (pluginResult == null) {
|
||||||
|
sb.append('J')
|
||||||
|
.append(jsPayloadOrCallbackId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int status = pluginResult.getStatus();
|
||||||
|
boolean noResult = status == PluginResult.Status.NO_RESULT.ordinal();
|
||||||
|
boolean resultOk = status == PluginResult.Status.OK.ordinal();
|
||||||
|
boolean keepCallback = pluginResult.getKeepCallback();
|
||||||
|
|
||||||
|
sb.append((noResult || resultOk) ? 'S' : 'F')
|
||||||
|
.append(keepCallback ? '1' : '0')
|
||||||
|
.append(status)
|
||||||
|
.append(' ')
|
||||||
|
.append(jsPayloadOrCallbackId)
|
||||||
|
.append(' ');
|
||||||
|
|
||||||
|
encodeAsMessageHelper(sb, pluginResult);
|
||||||
|
}
|
||||||
|
|
||||||
void encodeAsJsMessage(StringBuilder sb) {
|
void encodeAsJsMessage(StringBuilder sb) {
|
||||||
if (pluginResult == null) {
|
if (pluginResult == null) {
|
||||||
sb.append(jsPayloadOrCallbackId);
|
sb.append(jsPayloadOrCallbackId);
|
||||||
|
19
framework/src/org/apache/cordova/PluginResult.java
Executable file → Normal file
19
framework/src/org/apache/cordova/PluginResult.java
Executable file → Normal file
@ -18,6 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.cordova;
|
package org.apache.cordova;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
@ -29,6 +31,7 @@ public class PluginResult {
|
|||||||
private boolean keepCallback = false;
|
private boolean keepCallback = false;
|
||||||
private String strMessage;
|
private String strMessage;
|
||||||
private String encodedMessage;
|
private String encodedMessage;
|
||||||
|
private List<PluginResult> multipartMessages;
|
||||||
|
|
||||||
public PluginResult(Status status) {
|
public PluginResult(Status status) {
|
||||||
this(status, PluginResult.StatusMessages[status.ordinal()]);
|
this(status, PluginResult.StatusMessages[status.ordinal()]);
|
||||||
@ -80,6 +83,13 @@ public class PluginResult {
|
|||||||
this.encodedMessage = Base64.encodeToString(data, Base64.NO_WRAP);
|
this.encodedMessage = Base64.encodeToString(data, Base64.NO_WRAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The keepCallback and status of multipartMessages are ignored.
|
||||||
|
public PluginResult(Status status, List<PluginResult> multipartMessages) {
|
||||||
|
this.status = status.ordinal();
|
||||||
|
this.messageType = MESSAGE_TYPE_MULTIPART;
|
||||||
|
this.multipartMessages = multipartMessages;
|
||||||
|
}
|
||||||
|
|
||||||
public void setKeepCallback(boolean b) {
|
public void setKeepCallback(boolean b) {
|
||||||
this.keepCallback = b;
|
this.keepCallback = b;
|
||||||
}
|
}
|
||||||
@ -99,6 +109,14 @@ public class PluginResult {
|
|||||||
return encodedMessage;
|
return encodedMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getMultipartMessagesSize() {
|
||||||
|
return multipartMessages.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PluginResult getMultipartMessage(int index) {
|
||||||
|
return multipartMessages.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If messageType == MESSAGE_TYPE_STRING, then returns the message string.
|
* If messageType == MESSAGE_TYPE_STRING, then returns the message string.
|
||||||
* Otherwise, returns null.
|
* Otherwise, returns null.
|
||||||
@ -150,6 +168,7 @@ public class PluginResult {
|
|||||||
// Use BINARYSTRING when your string may contain null characters.
|
// Use BINARYSTRING when your string may contain null characters.
|
||||||
// This is required to work around a bug in the platform :(.
|
// This is required to work around a bug in the platform :(.
|
||||||
public static final int MESSAGE_TYPE_BINARYSTRING = 7;
|
public static final int MESSAGE_TYPE_BINARYSTRING = 7;
|
||||||
|
public static final int MESSAGE_TYPE_MULTIPART = 8;
|
||||||
|
|
||||||
public static String[] StatusMessages = new String[] {
|
public static String[] StatusMessages = new String[] {
|
||||||
"No result",
|
"No result",
|
||||||
|
Loading…
Reference in New Issue
Block a user