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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19177991/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 14:47:06  来源:igfitidea点击:

Asynchronous communication between Javascript and Phonegap Plugin

javaandroidcordovaphonegap-plugins

提问by Anas Azeem

So, everybody knows that we make a Class extending CordovaPluginand override the execute()and then creates a bridge between the JS and native Java (for Android). Further we use PluginResultto return the result back to the JS.

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

So, all of this happens when there is a request fired from the JS to the Java Plugin. My question is, how to send a result back to JS(and therefore to HTML) asynchronously ?

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

I don't know if the word asynchronousis right here. The thing is I want to send something back to the JS out of the blue (say, when wifi becomes enable/disable).

我不知道异步这个词是否在这里。问题是我想突然将一些东西发送回 JS(例如,当 wifi 启用/禁用时)。

I have already researched on this but haven't got anything which suits to my case.

我已经对此进行了研究,但没有任何适合我的情况。

The thing I've tried is -

我试过的事情是 -

  • Created a BroadcastReceiverlistening to the WiFievents using the WifiManagerclass.
  • Registered the receiver.
  • And finally, popping a Toastwhen WiFiis enabled/disabled, and sending the result using CallbackContext

    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, "Wifi Connected"))and for disconnected with a different message.

  • 使用该类创建了BroadcastReceiverWiFi事件的监听WifiManager
  • 注册接收器。
  • 最后,弹出启用/禁用Toastwhen WiFi,并使用CallbackContext

    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, "Wifi Connected"))和 for disconnected发送结果,并使用 不同的消息。

MyPlugin.java

我的插件

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"));
                }
            }           
        }

}

The Toastpops but the PluginResultisn't sent to the JS.

Toast持久性有机污染物,但PluginResult不发送给JS。



PS :Listening to WiFi events isn't my actual problem, I want to replicate the Android Bluetooth Chatapp in Phonegap. So, it has to be asynchronous in nature.

PS:收听WiFi事件不是我的实际问题,我想Android Bluetooth Chat在Phonegap中复制该应用程序。因此,它本质上必须是异步的。

采纳答案by Simon MacDonald

You are almost there but you need to setKeepCallback to true on your PluginResult. If you don't the subsequent results from the Java side will not have a callback on the JavaScript side. The best example of this type of coding is the Network plugin in Cordova core. Here is a link to the source:

你快到了,但你需要在你的 PluginResult 上 setKeepCallback 为 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

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

So you should update your code to:

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

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;
            }
        }
    }
}

回答by Lucidity

Answer to 'second callback' warning...

回答“第二次回调”警告..​​.

The Cordova source-code which triggers this warning can be found on line 57 here:

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

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

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

Thus - warning is caused because your CallbackContext object has 'finished=true'.

因此 - 警告是因为您的 CallbackContext 对象具有“finished=true”。

Most likely cause of this is you called: callbackContext.sendPluginResult(pluginResult);

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

Without first calling: pluginResult.setKeepCallback(true);

无需先调用: pluginResult.setKeepCallback(true);

If not... most likely you are unintentionally caching the CallbackContext object.

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

Your execute() function should assign CallbackContext each time it is called. See lines 125-127 in the code Simon linked to:

您的 execute() 函数应在每次调用时分配 CallbackContext。请参阅Simon 链接到代码中的第 125-127 行:

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

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

this.connectionCallbackContext = callbackContext;

...

The proper sequence of events in full:

完整的正确事件顺序:

  1. Make initial call to plugin.

  2. Plugin saves reference to passed in CallbackContext object.

  3. Keep CallbackContext object reference, while returning results with setKeepCallback(true).

  4. When the sequence is finished, return with setKeepCallback(false) (the default)

  1. 对插件进行初始调用。

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

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

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

Then later...

然后后来...

  1. Make another call to plugin.

  2. Plugin overwrites saved CallbackContext reference, replace with passed in object.

  1. 再次调用插件。

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

Then steps 3-4 same as above.

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

Hope that helps :)

希望有帮助:)