web-dev-qa-db-fra.com

Communication asynchrone entre le plug-in JavaScript et PhoneGap

Donc, tout le monde sait que nous faisons une classe s'étendant CordovaPlugin _ et remplacer la fonction execute() puis crée un pont entre le JS et le natif Java (pour Android) . En outre, nous utilisons PluginResult pour ramener le résultat à la JS.

Donc, tout cela se produit lorsqu'il y a une demande tirée du JS au Java plugin. Ma question est, Comment envoyer un résultat retour à JS (et donc à HTML) asynchrone?

Je ne sais pas si le mot asynchrone est juste ici. La chose est que je veux envoyer quelque chose à la JS hors du bleu (par exemple, lorsque WiFi devient activer/désactiver).

J'ai déjà étudié à ce sujet, mais je n'ai rien obtenu qui convient à mon cas.

La chose que j'ai essayée est -

  • Créé A BroadcastReceiver Écoute des événements WiFi à l'aide de la classe WifiManager.
  • Enregistré le destinataire.
  • Et enfin, popping a Toast lorsque WiFi est activé/désactivé et envoie le résultat en utilisant CallbackContext

    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, "Wifi Connected")) et pour déconnecté avec un message différent.

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

}

Le Toast pops mais le PluginResult n'est pas envoyé au JS.


PS : Écouter les événements WiFi n'est pas mon problème réel, je veux reproduire le Android Bluetooth Chat app in phonegap. Donc, il doit être de nature aussi asynchrone.

22
Anas Azeem

Vous êtes presque là, mais vous devez définirCallback sur TRUE sur votre pluginResult. Si vous ne le faites pas les résultats ultérieurs du Java côté n'auront pas de rappel sur le côté JavaScript. Le meilleur exemple de ce type de codage est le plugin réseau dans Cordova Core. Voici un Lien vers la source:

https://git-wip-us.apache.org/repos/asf?p=cordova-plugin-network-information.git ;A=blob ;f=src/andrroid/networkmanager.java ;h= E2AC500CCC885DB641D5DF6DAB8AE23026A5828; HB = HEAD

Vous devez donc mettre à jour votre code pour:

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

Réponse à "Second Rappel" Avertissement ...

Le code source Cordova qui déclenche cet avertissement peut être trouvé sur la ligne 57 ici:

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

Ainsi, l'avertissement est causé parce que votre objet CallbackContext a "fini = true".

La cause la plus probable de ceci est appelée: callbackContext.sendPluginResult(pluginResult);

Sans première appelant: pluginResult.setKeepCallback(true);

Sinon ... probablement vous êtes Mise en cache involontairement l'objet CallbackContext.

Votre fonction EXECUTE () doit affecter CallbackContext à chaque appel à appeler. Voir les lignes 125-127 dans le code SIMON lié à :

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

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

this.connectionCallbackContext = callbackContext;

...

La bonne séquence d'événements en entier:

  1. Faire appel initial au plugin.

  2. Le plugin enregistre la référence à un objet CallbackContext.

  3. Gardez la référence d'objet CallbackContext, tout en retournant les résultats avec SeepetCallback (true).

  4. Lorsque la séquence est terminée, retournez avec SeepetCallback (FALSE) (la valeur par défaut)

Puis plus tard ...

  1. Faire un autre appel au plugin.

  2. Le plugin remplace la référence de CallbackContext enregistré, remplacez par l'objet transmis.

Ensuite, étapes 3-4 identiques que ci-dessus.

J'espère que cela pourra aider :)

13
Tony Chen