Как работает функция JavaScriptJavascript?
Я пытаюсь использовать новый метод evaluateJavascript в Android 4.4, но все, что я когда-либо возвращаю, - это нулевой результат:
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
}
});
Как вернуть результат этому методу?
Обновление: Немного больше информации:
- У меня есть набор разрешений INTERNET
- У меня есть
setJavascriptEnabled(true);
- Исправлена строка апострофа:
return 'test';
,
- Исправленный объект JS:
return { test: 'this' }
-
console.log('test');
выполняется нормально.
- Установите
targetSdkVersion
в 19: Если ваше приложение использует WebView
Устройства: Оба Nexus 7 и Nexus 5 (Stock)
Ответы
Ответ 1
В этом примере используется пример метода methodJavascript:
https://github.com/GoogleChrome/chromium-webview-samples/tree/master/jsinterface-example
По существу, если javascript, который вы выполняете в WebView, возвращает значение, которое будет передано в обратном вызове.
Главное отметить, что строка, возвращаемая в OnReceiveValue, представляет собой значение JSON Value, JSON Object или JSON Array в зависимости от того, что вы возвращаете.
Следует отметить, что если вы вернете одно значение, вам нужно использовать setLenient (true) в считывателе JSON для его работы.
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
}
}
}
});
}
Причина, по которой вы все еще можете использовать синтаксический анализатор для строкового ответа, преобразуется в значение JSON, что означает, что он будет заключен в кавычки.
Например, если вы пошли:
mWebView.evaluateJavascript("(function() { return 'this'; })();", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Log.d("LogName", s); // Prints: "this"
}
});
Он напечатает эту строку, заключенную в двойные кавычки: "this".
Другие примеры, заслуживающие внимания:
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)
}
});
Ответ 2
ОК, так что получается result
здесь результат вызова Javascript - как если бы кто-то вводил эту команду в консоль Javascript.
Итак, чтобы получить результат, его нужно обернуть в функцию:
webView1.evaluateJavascript("(function() { return \"this\"; })();", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Log.d("LogName", s); // Prints 'this'
}
});
Это также будет работать:
webView1.evaluateJavascript("window.variable = \"asd\";", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Log.d("LogName", s); // Prints asd
}
});
Метод также обрабатывает объекты 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"}
}
});
Ответ 3
AndroidJSCore является хорошей альтернативой для оценки JavaScript, который не использует WebView.
Если вы хотите придерживаться WebView и вам нужно оценить JavaScript в более ранних версиях Android (4+), вот небольшая библиотека:
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)
}
});
Ответ 4
Подводя итог ответу @GauntFace и предоставляем альтернативное решение без использования парсера JSON:
Если ваша функция JS возвращает только String
, и вам интересно, почему эта строка искажена в Java, это потому, что она скрыта от 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"
}
});
(обратите внимание, что onReceiveValue
всегда предоставляет String
, в то время как функция JS может возвращать null
, литерал числа и т.д.)
Чтобы получить строковое значение так же, как в JS, если вы на 100% уверены, что ожидаете возврата String
, вам нужно будет JSON-unescape, например:
String unescaped = s.substring(1, s.length() - 1) // remove wrapping quotes
.replace("\\\\", "\\") // unescape \\ -> \
.replace("\\\"", "\""); // unescape \" -> "
Однако обратите внимание, что s
может быть строкой "null"
, если JS возвращает правильный null
, поэтому вам, очевидно, необходимо проверить это как самый первый шаг.
if ("null".equals(s)) {
...
} else {
// unescape JSON
}
Ответ 5
Каждый ответ великолепен. Я просто добавлю еще один момент. Не помещайте valuJavascript внутри метода с аннотацией @JavascripInterface следующим образом
@JavascripInterface
public void onData(){
mWebView.evaluateJavascript("javascript:executeNext()",null);
}
Так как он заблокирует поток JavaBridge. если вы хотите поместить в него defineJavascript. Сделай это так
@JavascripInterface
public void onData(){
mWebView.post(new Runnable() {
@Override
public void run() {
mWebView.evaluateJavascript("javascript:executeNext()",null);
}
});
}