开发一个cordova插件的时候,可能会遇到一个特别的action,需要调用后把java层获得的值多次返回到上端JS中。但是cordova默认是调用一次
callbackContext.error或者success
就会不再对上端JS继续传输数据
查看源码后得知 cordova做了这些操作:
1. java 层通过 callbackContext
将收集到的数据封装进 PluginResult
类中
2. 再通过 toSuccessCallbackstring
或者 toErrorCallbackString
方法将封装的数据传递到 JS 层并且调用
3. 最后根据 keepCallback 的参数,来调整 JS 端的 callback 是否保持活性
具体可以大概参考一下以下两个代码片段
public class PluginResult {
//将callbackContext返回的数据封装成一个JSON
public String getJSONString() {
return "{\"status\":" + this.status + ",\"message\":" + this.getMessage() + ",\"keepCallback\":" + this.keepCallback + "}";
}
//调用cordova.js文件中的callbackSuccess方法
public String toSuccessCallbackString(String callbackId) {
return "cordova.callbackSuccess('"+callbackId+"',"+this.getJSONString()+");";
}
//调用cordova.js文件中的callbackError方法
public String toErrorCallbackString(String callbackId) {
return "cordova.callbackError('"+callbackId+"', " + this.getJSONString()+ ");";
}
}
cordova.js
var cordova = {
/**
* Called by native code when returning successful result from an action.
* PluginResult.java中toSuccessCallbackString实际调用的js方法
*/
callbackSuccess: function(callbackId, args) {
cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
},
/**
* Called by native code when returning error result from an action.
*/
callbackError: function(callbackId, args) {
// TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
// Derive success from status.
cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
},
/**
* Called by native code when returning the result from an action.
* 调用回调函数
*/
callbackFromNative: function(callbackId, isSuccess, status, args, keepCallback) {
try {
//根据callbackId获取是success还是error回调
var callback = cordova.callbacks[callbackId];
if (callback) {
if (isSuccess && status == cordova.callbackStatus.OK) {
//调用success的函数
callback.success && callback.success.apply(null, args);
} else if (!isSuccess) {
//调用error的函数
callback.fail && callback.fail.apply(null, args);
}
// Clear callback if not expecting any more results
//如果keepCallback为false,则回调一次立即停止(keepCallback默认是false)
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;
}
},
};
我的思路是自定义一个
customCallbackContext
对原来的CallbackContext
进行功能的扩展,以下我自定义的CustomCallbackContext.java
,重点可以看sendPluginResult
方法。
外部调用只需要调用callbackContext.success("msg",true)
,便可以一直保持JS端接口的活性,调用callbackContext.success("msg",false)或callbackContext.success("msg")
就可以使用执行一次就失活的callback
protected static class CustomCallbackContext extends CallbackContext {
public static CustomCallbackContext newInstance(CallbackContext callbackContext) {
CordovaWebView webView = null;
Class cls = callbackContext.getClass();
try {
Field field = cls.getDeclaredField("webView");
field.setAccessible(true);
webView = (CordovaWebView) field.get(callbackContext);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return new CustomCallbackContext(callbackContext.getCallbackId(), webView);
}
public CustomCallbackContext(String callbackId, CordovaWebView webView) {
super(callbackId, webView);
}
//重写sendPluginResult方法,添加是否保持活性的参数
public void sendPluginResult(PluginResult pluginResult, boolean isKeep) {
//最关键的地方,给pluginResult设置是否保证活性
pluginResult.setKeepCallback(isKeep);
super.sendPluginResult(pluginResult);
}
/********************以下是模仿CallbackContext写的success和error方法*************************/
/**
* success回调,isKeep 为true的时候,可以持续把数据返回到js层中
*
* @param message
* @param isKeep
*/
public void success(JSONObject message, boolean isKeep) {
sendPluginResult(new PluginResult(PluginResult.Status.OK, message), isKeep);
}
/**
* success回调,isKeep 为true的时候,可以持续把数据返回到js层中
*
* @param message
* @param isKeep
*/
public void success(String message, boolean isKeep) {
sendPluginResult(new PluginResult(PluginResult.Status.OK, message), isKeep);
}
/**
* success回调,isKeep 为true的时候,可以持续把数据返回到js层中
*
* @param message
* @param isKeep
*/
public void success(JSONArray message, boolean isKeep) {
sendPluginResult(new PluginResult(PluginResult.Status.OK, message), isKeep);
}
/**
* success回调,isKeep 为true的时候,可以持续把数据返回到js层中
*
* @param message
* @param isKeep
*/
public void success(byte[] message, boolean isKeep) {
sendPluginResult(new PluginResult(PluginResult.Status.OK, message), isKeep);
}
/**
* success回调,isKeep 为true的时候,可以持续把数据返回到js层中
*
* @param message
* @param isKeep
*/
public void success(int message, boolean isKeep) {
sendPluginResult(new PluginResult(PluginResult.Status.OK, message), isKeep);
}
/**
* success回调,isKeep 为true的时候,可以持续把数据返回到js层中
*
* @param isKeep
*/
public void success(boolean isKeep) {
sendPluginResult(new PluginResult(PluginResult.Status.OK), isKeep);
}
/**
* error回调,isKeep 为true的时候,可以持续把数据返回到js层中
*
* @param message
* @param isKeep
*/
public void error(JSONObject message, boolean isKeep) {
sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message), isKeep);
}
/**
* error回调,isKeep 为true的时候,可以持续把数据返回到js层中
*
* @param message
* @param isKeep
*/
public void error(String message, boolean isKeep) {
sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message), isKeep);
}
/**
* error回调,isKeep 为true的时候,可以持续把数据返回到js层中
*
* @param message
* @param isKeep
*/
public void error(int message, boolean isKeep) {
sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message), isKeep);
}
}