¿Cómo funciona evaluateJavascript?


Estoy tratando de usar el nuevo método evaluateJavascript en Android 4.4, pero todo lo que obtengo es un resultado nulo:

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

¿Cómo devuelvo un resultado a este método?

Actualización: Poco más información:

  1. Tengo el permiso de INTERNET establecido
  2. Tengo setJavascriptEnabled(true);
  3. Cadena de apóstrofo probada: return 'test';,
  4. Objeto JS probado: return { test: 'this' }
  5. console.log('test'); está siendo ejecutado multa.
  6. Establecer targetSdkVersion a 19 según: Si tu app usa WebView

Dispositivos: Ambos Nexus 7 y Nexus 5 (Stock)

Author: CodingIntrigue, 2013-11-05

4 answers

Hay un ejemplo del método evaluateJavascript que se utiliza en esta muestra:

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

Esencialmente si el javascript que ejecuta en la WebView devuelve un valor, se pasará en la devolución de llamada.

Lo principal a tener en cuenta es que la cadena devuelta en OnReceiveValue es un Valor JSON, un objeto JSON o una matriz JSON dependiendo de lo que devuelva.

Cosas para tenga en cuenta que si devuelve un solo valor, debe usar setLenient(true) en un lector JSON para que funcione.

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

La razón por la que aún puede querer usar un analizador para una respuesta de cadena es que se convierte a un valor JSON, lo que significa que estará envuelto entre comillas.

Por ejemplo, si usted fue:

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

Imprimiría la cadena this, envuelta entre comillas dobles: "this".

Otros ejemplos dignos de mención:

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)
    }
});
 51
Author: Gaunt Face,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-22 15:54:47

OK, entonces resulta que el resultaquí está el resultado de la llamada a Javascript - como si uno estuviera ingresando el comando en una consola Javascript.

Así que para obtener un resultado, necesita estar envuelto en una función:

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

Esto también funcionará:

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

El método también maneja objetos 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
Author: CodingIntrigue,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-05 14:06:43

AndroidJSCore es una buena alternativa para evaluar JavaScript que no utiliza una vista WEB.

Si desea seguir con WebView y necesita evaluar JavaScript en versiones anteriores de Android (4+), aquí hay una pequeña biblioteca:

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
Author: Evgenii,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-06 01:13:20

Para resumir la respuesta de @GauntFace y proporcionar una solución alternativa sin usar el analizador JSON:

Si su función JS devuelve solo un String y se pregunta por qué la cadena está destrozada en Java, es porque es JSON-escaped.

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

(tenga en cuenta que onReceiveValue siempre proporciona un String mientras que la función JS puede devolver un null, un número literal, etc.)

Para obtener el valor de la cadena igual que en JS, si está 100% seguro de que está esperando un String devuelto, usted necesitaría JSON-unescape él, por ejemplo así:

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

Sin Embargo, tenga en cuenta que s puede ser una cadena "null" si JS devuelve adecuado null, por lo que, obviamente, necesita comprobar que, como primer paso.

if ("null".equals(s)) {
   ...
} else {
   // unescape JSON
}
 2
Author: jakub.g,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-06 13:13:19