Javascript和Phonegap插件之间的异步通信

时间:2013-10-04 09:37:26

标签: java android cordova phonegap-plugins

所以,每个人都知道我们创建一个扩展CordovaPlugin的类并覆盖execute(),然后在JS和本机Java(用于Android)之间创建一个桥梁。此外,我们使用PluginResult将结果返回给JS。

因此,当JS向Java插件发出请求时,所有这些都会发生。我的问题是,如何将结果发送回JS (因此发送到HTML)异步?

我不知道这个词是否< strong>异步就在这里。问题是我想要发送一些东西回到JS(比如,当wifi变为启用/禁用时)。

我已经研究过这个但是没有任何适合我的情况。

我尝试过的是 -

  • 使用BroadcastReceiver类创建了一个WiFi来监听WifiManager个事件。
  • 注册接收者。
  • 最后,在启用/禁用Toast时弹出WiFi,并使用CallbackContext发送结果

    {{1}并且与其他消息断开连接。

MyPlugin.java

callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, "Wifi 
Connected"))

import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaPlugin; import org.apache.cordova.PluginResult; import org.json.JSONArray; ... public class MyPlugin extends CordovaPlugin { private WifiReceiver wifiBroadcastReceiver = null; private CallbackContext callbackContext = null; ... public MyPlugin() { wifiBroadcastReceiver = new WifiReceiver(); ... } ... public boolean execute(String action, final JSONArray args, final CallbackContext callbackId) throws JSONException { IntentFilter wifiFilter = new IntentFilter(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); cordova.getActivity().registerReceiver(wifiBroadcastReceiver, wifiFilter); this.callbackContext = callbackId; ... } public class WifiReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) { if (intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)) { Toast.makeText(cordova.getActivity(), "Wifi Connected", Toast.LENGTH_SHORT).show(); callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, "Wifi Connected")); } else { Toast.makeText(cordova.getActivity(), "Wifi Disconnected", Toast.LENGTH_SHORT).show(); callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, "Wifi Disconnected")); } } } } 弹出,但Toast未发送给JS。


PS:听取WiFi事件不是我的实际问题,我想在Phonegap中复制PluginResult应用。因此,它必须是异步的。

2 个答案:

答案 0 :(得分:16)

你几乎就在那里,但你需要在PluginResult上将KeepCallback设置为true。如果不这样做,Java端的后续结果将不会在JavaScript端进行回调。这种编码的最好例子是Cordova核心中的网络插件。这是源的链接:

https://git-wip-us.apache.org/repos/asf?p=cordova-plugin-network-information.git;a=blob;f=src/android/NetworkManager.java;h=e2ac500ccc885db641d5df6dab8eae23026a5828;hb=HEAD

因此,您应该将代码更新为:

public boolean execute(String action, final JSONArray args,
        final CallbackContext callbackId) throws JSONException {
    IntentFilter wifiFilter = new IntentFilter(
            WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
    cordova.getActivity().registerReceiver(wifiBroadcastReceiver,
            wifiFilter);
    this.callbackContext = callbackId;
    PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
    result.setKeepCallback(true);
    this.callbackContext.sendPluginResult(result);
    return true;
}

public class WifiReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
            PluginResult result;
            if (intent.getBooleanExtra(
                    WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)) {
                Toast.makeText(cordova.getActivity(), "Wifi Connected",
                        Toast.LENGTH_SHORT).show();
                result = new PluginResult(PluginResult.Status.OK,
                        "Wifi Connected");
            } else {
                Toast.makeText(cordova.getActivity(), "Wifi Disconnected",
                        Toast.LENGTH_SHORT).show();
                result = new PluginResult(PluginResult.Status.ERROR,
                        "Wifi Disconnected");
            }

            result.setKeepCallback(false);
            if (callbackContext != null) {
                callbackContext.sendPluginResult(result);
                callbackContext = null;
            }
        }
    }
}

答案 1 :(得分:11)

回答'第二回调'警告......

触发此警告的Cordova源代码可在第57行找到:

https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/CallbackContext.java

因此 - 引发警告是因为您的CallbackContext对象具有'finished = true'。

最有可能的原因是你打电话:callbackContext.sendPluginResult(pluginResult);

没有先致电:pluginResult.setKeepCallback(true);

如果不是......很可能你无意中缓存了CallbackContext对象。

你的execute()函数应该在每次调用时分配CallbackContext。请参阅code Simon linked to中的第125-127行:

public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {

if (action.equals("getConnectionInfo")) {`

this.connectionCallbackContext = callbackContext;

...

完整的事件顺序:

  1. 初次调用插件。

  2. 插件保存对传入的CallbackContext对象的引用。

  3. 保留CallbackContext对象引用,同时使用setKeepCallback(true)返回结果。

  4. 序列完成后,返回setKeepCallback(false)(默认值)

  5. 然后......

    1. 再次调用插件。

    2. 插件会覆盖保存的CallbackContext引用,替换为传入的对象。

    3. 然后步骤3-4与上述相同。

      希望有所帮助:)