Ответ 1
Я понял, в чем проблема: отсутствующие кавычки в параметре testEcho(). Вот как я получил звонок на работу:
myWebView.loadUrl("javascript:testEcho('Hello World!')");
Я пытаюсь вызвать некоторые функции javascript
, сидящие на странице html
, запущенной внутри android webview
. Довольно просто, что код пытается сделать ниже - из приложения Android, вызовите функцию javascript
с тестовым сообщением, которое inturn вызывает функцию java обратно в приложении Android, которое отображает тестовое сообщение через тост.
Функция javascript
выглядит так:
function testEcho(message){
window.JSInterface.doEchoTest(message);
}
Из WebView я попытался вызвать javascript
следующие способы без везения:
myWebView.loadUrl("javascript:testEcho(Hello World!)");
mWebView.loadUrl("javascript:(function () { " + "testEcho(Hello World!);" + "})()");
Я включил javascript
в WebView
myWebView.getSettings().setJavaScriptEnabled(true);
// register class containing methods to be exposed to JavaScript
myWebView.addJavascriptInterface(myJSInterface, "JSInterface");
И heres Java
Класс
public class JSInterface{
private WebView mAppView;
public JSInterface (WebView appView) {
this.mAppView = appView;
}
public void doEchoTest(String echo){
Toast toast = Toast.makeText(mAppView.getContext(), echo, Toast.LENGTH_SHORT);
toast.show();
}
}
Я потратил много времени на поиски, чтобы понять, что я могу делать неправильно. Все примеры, которые я нашел, используют этот подход. Кто-нибудь видит здесь что-то не так?
Изменить: Есть несколько других внешних файлов javascript
, на которые ссылаются и используются в html
, могут ли они быть проблемой?
Я понял, в чем проблема: отсутствующие кавычки в параметре testEcho(). Вот как я получил звонок на работу:
myWebView.loadUrl("javascript:testEcho('Hello World!')");
Из kitkat и далее используйте метод javascript вместо loadUrl, чтобы вызвать функции javascript, как показано ниже
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript("enable();", null);
} else {
webView.loadUrl("javascript:enable();");
}
public void run(final String scriptSrc) {
webView.post(new Runnable() {
@Override
public void run() {
webView.loadUrl("javascript:" + scriptSrc);
}
});
}
Я создал хорошую оболочку для вызова методов JavaScript; это также показывает ошибки JavaScript в журнале:
private void callJavaScript(String methodName, Object...params){
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("javascript:try{");
stringBuilder.append(methodName);
stringBuilder.append("(");
for (int i = 0; i < params.length; i++) {
Object param = params[i];
if(param instanceof String){
stringBuilder.append("'");
stringBuilder.append(param.toString().replace("'", "\\'"));
stringBuilder.append("'");
}
if(i < params.length - 1){
stringBuilder.append(",");
}
}
stringBuilder.append(")}catch(error){Android.onError(error.message);}");
webView.loadUrl(stringBuilder.toString());
}
Вы должны добавить это тоже:
private class WebViewInterface{
@JavascriptInterface
public void onError(String error){
throw new Error(error);
}
}
И добавьте этот интерфейс в ваше веб-представление:
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebViewInterface(), "AndroidErrorReporter");
Да, у вас есть синтаксическая ошибка. Если вы хотите получать ошибки Javascript и операторы печати в logcat, вы должны реализовать метод onConsoleMessage(ConsoleMessage cm)
в вашем WebChromeClient. Он дает полные трассировки стека, такие как веб-консоль (элемент Inspect). Вот метод.
public boolean onConsoleMessage(ConsoleMessage cm)
{
Log.d("Message", cm.message() + " -- From line "
+ cm.lineNumber() + " of "
+ cm.sourceId() );
return true;
}
После реализации вы получите ваши ошибки Javascript и напечатаете операторы (console.log
) на вашем logcat.
Модификация ответа @Ilya_Gazman
private void callJavaScript(WebView view, String methodName, Object...params){
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("javascript:try{");
stringBuilder.append(methodName);
stringBuilder.append("(");
String separator = "";
for (Object param : params) {
stringBuilder.append(separator);
separator = ",";
if(param instanceof String){
stringBuilder.append("'");
}
stringBuilder.append(param.toString().replace("'", "\\'"));
if(param instanceof String){
stringBuilder.append("'");
}
}
stringBuilder.append(")}catch(error){console.error(error.message);}");
final String call = stringBuilder.toString();
Log.i(TAG, "callJavaScript: call="+call);
view.loadUrl(call);
}
будет правильно создавать вызовы JS, например
callJavaScript(mBrowser, "alert", "abc", "def");
//javascript:try{alert('abc','def')}catch(error){console.error(error.message);}
callJavaScript(mBrowser, "alert", 1, true, "abc");
//javascript:try{alert(1,true,'abc')}catch(error){console.error(error.message);}
Обратите внимание, что объекты не будут переданы правильно - но вы можете сериализовать их перед передачей в качестве аргумента.
Кроме того, я изменил, где идет ошибка, я перенаправил ее в журнал консоли, который можно прослушать:
webView.setWebChromeClient(new CustomWebChromeClient());
и клиент
class CustomWebChromeClient extends WebChromeClient {
private static final String TAG = "CustomWebChromeClient";
@Override
public boolean onConsoleMessage(ConsoleMessage cm) {
Log.d(TAG, String.format("%s @ %d: %s", cm.message(),
cm.lineNumber(), cm.sourceId()));
return true;
}
}