Cordova:如何编写可以重复调用 Javascript 回调的本机插件?

Posted

技术标签:

【中文标题】Cordova:如何编写可以重复调用 Javascript 回调的本机插件?【英文标题】:Cordova: How to write native plugins that can repeatedly invoke a Javascript callback? 【发布时间】:2014-10-18 10:46:06 【问题描述】:

在开发 Cordova 插件时,我找到的所有教程都是这样的:

文件:AwesomePlugin.js

var AwesomePlugin = 
  kungfuGripAction = function(target, successCallback, failureCallback) 
    return cordova.exec(
      successCallback,
      failureCallback,
      'AwesomePluginClass',
      'kungfuGripAction',
      [target]
    );
  
;

module.exports = AwesomePlugin;

文件:AwesomePluginClass.java

@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException 
    if (ACTION_KUNGFU_GRIP.equals(action)) 
        JSONObject target = args.getJSONObject(0);
        if (gripTarget(target)) 
            callbackContext.success("Target successfully gripped.");
            return true;
         else 
            callbackContext.error("Could not grip target.");
            return false;
        
    

    Log.d(LOG_TAG, "INVALID ACTION! " + action);
    callbackContext.error("Invalid action: " + action);
    return false;

文件:clientCode.js

AwesomePlugin.kungfuGripAction(cobraEnemy, function(ok)  , function(err)  );

在上面的代码中,回调只能被调用一次然后被释放。如果您尝试调用回调上下文对象的.success().error() 方法,它将不起作用,您将收到一条日志消息:

Attempted to send a second callback for ID: AwesomePlugin2982699494<BR>W/CordovaPlugin(976) Result was: "Target successfully gripped."

似乎不可能编写带有可重复调用的回调的方法,因为 .success().error() 是唯一记录在案的从本机插件代码中调用回调的方法。虽然这主要是我们想要的,但有时我们希望插件重复执行回调。例如:

AwesomePlugin.kungfuGripAction(cobraEnemy, function(ok) 
  // After successful grip, punch repeatedly and update life meter.
  AwesomePlugin.punchRepeatedly(cobraEnemy, function(hits) 
    updateLifeMeter(cobraEnemy, hits);
  , function(err)  );
, function(err)  );

上面的AwesomePlugin.punchRepeatedly() 将重复执行(可能在单独的线程中)并在每次成功执行时调用function(hits)。如果以事实上的方式实现(使用一次性回调),则必须在回调中使用循环(这很糟糕,因为它是非异步的)或尾部调用 AwesomePlugin.punchRepeatedly()(容易出错)。

在本机代码中实现punchRepeatedly() 以便能够注册一次回调然后重复执行它的正确方法是什么?

【问题讨论】:

【参考方案1】:

我认为,您可以使用 pluginResult 并将 keepCallback 属性设置为 true

PluginResult result = new PluginResult(PluginResult.Status.OK, "YOUR_MESSAGE");
// PluginResult result = new PluginResult(PluginResult.Status.ERROR, "YOUR_ERROR_MESSAGE");
result.setKeepCallback(true);
callbackContext.sendPluginResult(result);

您应该可以通过这种方式多次调用回调。

【讨论】:

谢谢,这行得通。 PluginResult.setKeepCallback(true) 是关键。 @n.abing 这不是在每次发送新回调时通过 status.ok 多次触发成功回调吗? @TimothyShamilov 不,它不会那样做。自从我在 Cordova 中编写任何内容以来已经有很长时间了,但 IIRC result.setKeepCallback(true) 仅确保当 result 被销毁时回调函数不会被销毁。如有疑问,请使用来源:)【参考方案2】:

在 jonas 的回答中,每次调用 sendPluginResult 时,都必须发送相同的值。所以我改变了 PluginResult 类来添加一个这样的方法:

 public void setStrMessage(String strMessage)
    this.strMessage = strMessage;

这样,我可以设置我要发送到javascript端的消息。

【讨论】:

您通常应该避免直接修改框架代码。当您升级 Cordova 框架时,您的更改将丢失。您也不需要更改插件结果中的消息,因为您在创建新实例然后将其发送到回调时已经设置了该消息。您唯一可能想要这样做的情况是,如果您在插件中重复使用 PluginResult 的单个实例,这也是一个坏主意。 你是对的。但我的意思是通过设置 setKeepCallback (true) 来重用 Pluginresult 的单个实例,那么每次发送不同消息的更好方法是什么?在 swift 语言中我可以使用扩展 什么意思?您不必重复使用 PluginResult 的单个实例。您可以在每次需要将结果发回回调时实例化一个新的PluginResult,并根据需要使用不同的消息。使用result.keepCallback(true) 只会告诉callbackContext.sendPluginResult() 不要将回调标记为“已使用”,以便您可以在再次发送结果时重用callbackContext 我明白你的意思了!你的意思是每个 Pluginresult 实例都应该 setKeepCallback(true) 吗?!非常感谢 ? 是的,在你创建PluginResult的新实例后,你应该在sendPluginResult()中使用它之前使用setKeepCallback(true),否则你会得到上面描述的错误。

以上是关于Cordova:如何编写可以重复调用 Javascript 回调的本机插件?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 android 中远程更新我的 cordova/phonegap 移动应用程序?

H5页面中如何调用cordova的插件?

使用JavaScript调用手机平台上的原生API

通过 Cordova 插件从 Objective-C 调用 Javascript

如何在 Cordova 中创建基本的重复回调?

如何使用 cordova 3.x 新的命令行界面在主要活动中编写代码