Как работает Javascript?
Я пытаюсь использовать новый метод valuJavascript в 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
}
});
Как мне вернуть результат этому методу?
Обновление: немного больше информации:
- У меня есть набор разрешений ИНТЕРНЕТ
- я имею
setJavascriptEnabled(true);
- Пробовал апострофную строку:
return 'test';
, - Испытанный объект JS:
return { test: 'this' }
console.log('test');
выполняется хорошо.- Задавать
targetSdkVersion
до 19 согласно: если ваше приложение использует WebView
Устройства: как Nexus 7, так и Nexus 5 (сток)
4 ответа
Ниже приведен пример использования метода valuJavascript в этом примере:
https://github.com/GoogleChrome/chromium-webview-samples/tree/master/jsinterface-example
По сути, если javascript, который вы выполняете в WebView, возвращает значение, оно будет передано в обратном вызове.
Главное, на что нужно обратить внимание, это то, что String, возвращаемая в 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, заключенная в двойные кавычки: "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)
}
});
Ок, так получается 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"}
}
});
У всех отличный ответ. Я просто добавлю еще один момент. Не помещайте valuJavascript внутри метода с аннотацией @JavascripInterface следующим образом
@JavascripInterface
public void onData(){
mWebView.evaluateJavascript("javascript:executeNext()",null);
}
Так как он заблокирует поток JavaBridge. если вы хотите поместить в него valuJavascript. Сделай это так
@JavascripInterface
public void onData(){
mWebView.post(new Runnable() {
@Override
public void run() {
mWebView.evaluateJavascript("javascript:executeNext()",null);
}
});
}
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)
}
});
Чтобы суммировать ответ @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
}
Важный совет:
перед звонкомevaluateJavascript
вам необходимо включить JavaScript для вашего WebView. Иначе результата не будет.
WebSettings settings = yourWebview.getSettings();
settings.setJavaScriptEnabled(true);