web-dev-qa-db-ja.com

JavascriptとPhonegapプラグイン間の非同期通信

したがって、CordovaPluginを拡張するクラスを作成してexecute()をオーバーライドし、JSとネイティブJava(Androidの場合)の間にブリッジを作成することを誰もが知っています。 。さらに、PluginResultを使用して結果をJSに返します。

したがって、JSからJavaプラグインへのリクエストが発生したときに、これらすべてが発生します。私の質問は、結果をJSに返す方法(そしてしたがって、HTMLへ)非同期に?

単語非同期がここにあるかどうかはわかりません。問題は、すぐにJSに何かを送り返すことです(たとえば、wifiが有効/無効になったとき)。

私はすでにこれについて調査しましたが、私のケースに合うものはありません。

私が試したことは-

  • BroadcastReceiverクラスを使用してWiFiイベントをリスニングするWifiManagerを作成しました。
  • 受信機を登録しました。
  • そして最後に、Toastが有効/無効になっているときにWiFiをポップし、CallbackContextを使用して結果を送信します

    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, "Wifi Connected"))および別のメッセージで切断された場合。

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

}

Toastはポップしますが、PluginResultはJSに送信されません。


PS: WiFiイベントをリッスンすることは私の実際の問題ではありません。Android Bluetooth Chat Phonegapのアプリ。したがって、それは本質的に非同期でなければなりません。

22
Anas Azeem

あと少しですが、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;
            }
        }
    }
}
18
Simon MacDonald

「2番目のコールバック」警告への回答...

この警告をトリガーする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を割り当てる必要があります。にリンクされている コードSimonの125〜127行目を参照してください

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

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

this.connectionCallbackContext = callbackContext;

...

完全なイベントの適切なシーケンス:

  1. プラグインを最初に呼び出します。

  2. プラグインは、渡されたCallbackContextオブジェクトへの参照を保存します。

  3. SetKeepCallback(true)で結果を返す間、CallbackContextオブジェクト参照を保持します。

  4. シーケンスが終了したら、setKeepCallback(false)で戻ります(デフォルト)。

じゃあ後で...

  1. プラグインをもう一度呼び出します。

  2. プラグインは、保存されたCallbackContext参照を上書きし、渡されたオブジェクトで置き換えます。

次に、上記と同じ手順3〜4を実行します。

それが役に立てば幸い:)

13
Tony Chen