web-dev-qa-db-fra.com

Comment fonctionne evaluationJavascript?

J'essaie d'utiliser la nouvelle méthode assessmentJavascript dans Android 4.4, mais tout ce que je reçois est un résultat nul:

webView1.evaluateJavascript("return \"test\";", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s); // Log is written, but s is always null
    }
});

Comment puis-je retourner un résultat à cette méthode?

Mise à jour: Un peu plus d'infos:

  1. J'ai le jeu d'autorisations INTERNET
  2. J'ai setJavascriptEnabled(true);
  3. Essayé chaîne d'apostrophe: return 'test';,
  4. Objet JS essayé: return { test: 'this' }
  5. console.log('test'); est bien exécuté.
  6. Définissez targetSdkVersion sur 19 selon: Si votre application utilise WebView

Appareils: Nexus 7 et Nexus 5 (Stock)

42
CodingIntrigue

Voici un exemple de la méthode assessmentJavascript utilisée dans cet exemple:

https://github.com/GoogleChrome/chromium-webview-samples/tree/master/jsinterface-example

Essentiellement, si le javascript que vous exécutez dans WebView renvoie une valeur, il sera transmis dans le rappel.

La principale chose à noter est que la chaîne renvoyée dans OnReceiveValue est une valeur JSON, un objet JSON ou un tableau JSON, en fonction de ce que vous retournez.

Ce qu'il faut noter à ce sujet, c'est que si vous renvoyez une valeur unique, vous devez utiliser setLenient (true) sur un lecteur JSON pour que cela fonctionne.

     if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KitKat) {
        // In KitKat+ you should use the evaluateJavascript method
        mWebView.evaluateJavascript(javascript, new ValueCallback<String>() {
            @TargetApi(Build.VERSION_CODES.HONEYCOMB)
            @Override
            public void onReceiveValue(String s) {
                JsonReader reader = new JsonReader(new StringReader(s));

                // Must set lenient to parse single values
                reader.setLenient(true);

                try {
                    if(reader.peek() != JsonToken.NULL) {
                        if(reader.peek() == JsonToken.STRING) {
                            String msg = reader.nextString();
                            if(msg != null) {
                                Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
                            }
                        }
                    }
                } catch (IOException e) {
                    Log.e("TAG", "MainActivity: IOException", e);
                } finally {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        // NOOP
                    }
                }
            }
        });
    }

Si vous souhaitez toujours utiliser un analyseur syntaxique pour une réponse de chaîne, c'est parce qu'il est converti en une valeur JSON, ce qui signifie qu'il sera entouré de guillemets.

Par exemple si vous êtes allé:

mWebView.evaluateJavascript("(function() { return 'this'; })();", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s); // Prints: "this"
    }
});

Cela afficherait la chaîne this, entourée de guillemets: "this".

Autres exemples à noter:

mWebView.evaluateJavascript("(function() { return null; })();", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s); // Prints the string 'null' NOT Java null
    }
});

mWebView.evaluateJavascript("(function() { })();", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s); //s is Java null
    }
});

mWebView.evaluateJavascript("(function() { return ''; })();", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s); // Prints "" (Two double quotes)
    }
});
58
Matt Gaunt

OK, il s’avère que la result est le résultat de l’appel Javascript - comme si l’on introduisait la commande dans une console Javascript.

Donc, pour obtenir un résultat, il doit être encapsulé dans une fonction:

webView1.evaluateJavascript("(function() { return \"this\"; })();", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s); // Prints 'this'
    }
});

Cela fonctionnera également:

webView1.evaluateJavascript("window.variable = \"asd\";", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s); // Prints asd
    }
});

La méthode gère également les objets Javascript:

webView1.evaluateJavascript("(function() { return { var1: \"variable1\", var2: \"variable2\" }; })();", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s); // Prints: {"var1":"variable1","var2":"variable2"}
    }
});
10
CodingIntrigue

AndroidJSCore est une bonne alternative pour évaluer JavaScript qui n'utilise pas WebView.

Si vous souhaitez vous en tenir à WebView et que vous avez besoin d'évaluer JavaScript dans les versions précédentes d'Android (4+), voici une petite bibliothèque:

https://github.com/evgenyneu/js-evaluator-for-Android

jsEvaluator.evaluate("put your JavaScript code", new JsCallback() {
  @Override
  public void onResult(final String result) {
    // get result here (optional)
  }
});
7
Evgenii

Pour résumer la réponse de @GauntFace et fournir une solution alternative sans utiliser l’analyseur JSON:

Si votre fonction JS retourne juste une String et que vous vous demandez pourquoi la chaîne est mutilée en Java, c'est parce qu'elle est échappée en JSON.

mWebView.evaluateJavascript("(function() { return 'Earvin \"Magic\" Johnson'; })();", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("LogName", s);
        // expected: s == Earvin "Magic" Johnson
        // actual:   s == "Earvin \"Magic\" Johnson"
    }
});

(notez que onReceiveValue fournit toujours une String alors que la fonction JS peut renvoyer une null, un nombre littéral, etc.)

Pour obtenir la même valeur de chaîne que dans JS, si vous êtes absolument sûr que vous attendez un String correct renvoyé, vous devez le supprimer par JSON, par exemple, comme ceci:

String unescaped = s.substring(1, s.length() - 1)  // remove wrapping quotes
                     .replace("\\\\", "\\")        // unescape \\ -> \
                     .replace("\\\"", "\"");       // unescape \" -> "

Cependant, notez que s peut être une chaîne "null" si JS renvoie null correct. Vous devez donc évidemment vérifier cela dès la première étape.

if ("null".equals(s)) {
   ...
} else {
   // unescape JSON
}
2
jakub.g

La réponse de tout le monde est géniale. Je viens d'ajouter un autre point. Ne mettez pas evaluationJavascript dans la méthode avec l'annotation @JavascripInterface comme ceci

    @JavascripInterface
    public void onData(){ 
            mWebView.evaluateJavascript("javascript:executeNext()",null);
    }  

Parce que cela bloquera le fil JavaBridge . Si vous voulez y placerJavaScript. Faites-le avec cette voie

    @JavascripInterface
    public void onData(){
        mWebView.post(new Runnable() {
            @Override
            public void run() {
                mWebView.evaluateJavascript("javascript:executeNext()",null);
            }
        });

    }
1
littlebear333