Android 在 WebView 中调用 JavaScript 函数

IT技术 javascript android webview android-webview
2021-01-14 17:41:54

我正在尝试调用一些 javascript 函数,这些函数位于在 android webview 中运行的 html 页面中。代码在下面尝试执行的操作非常简单 - 从 android 应用程序中,调用带有测试消息的 javascript 函数,该函数又调用回通过 toast 显示测试消息的 android 应用程序中的 java 函数。

javascript 函数如下所示:

function testEcho(message){
     window.JSInterface.doEchoTest(message);
}

在 WebView 中,我尝试通过以下方式调用 javascript,但没有成功:

myWebView.loadUrl("javascript:testEcho(Hello World!)");
mWebView.loadUrl("javascript:(function () { " + "testEcho(Hello World!);" + "})()");

我确实在 WebView 上启用了 javascript

myWebView.getSettings().setJavaScriptEnabled(true);
// register class containing methods to be exposed to JavaScript
myWebView.addJavascriptInterface(myJSInterface, "JSInterface"); 

这是 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();
    }
}

我花了很多时间在谷歌上搜索,看看我可能做错了什么。我发现的所有示例都使用这种方法。有人看到这里有什么问题吗?

编辑: 在 html 中引用和使用了其他几个外部 javascript 文件,它们可能是问题吗?

6个回答

我想出了问题所在: testEcho() 参数中缺少引号。这就是我接到工作电话的方式:

myWebView.loadUrl("javascript:testEcho('Hello World!')");
2021-03-12 17:41:54
@KovácsImre String.Format("javascript: testEcho('%d', '%d', '%d')", 1, 2, 3); 我猜
2021-03-12 17:41:54
谢谢,同时我也发现了。
2021-03-19 17:41:54
从 KitKat 开始,有evaluateJavascript 方法,检查stackoverflow.com/a/32163655/3063226
2021-03-27 17:41:54
这很好,但是如何将 Java 对象作为参数传递给 JavaScript 函数呢?
2021-03-30 17:41:54

从kitkat 开始,使用evaluateJavascript 方法代替loadUrl 来调用javascript 函数,如下所示

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
        webView.evaluateJavascript("enable();", null);
    } else {
        webView.loadUrl("javascript:enable();");
    }
@Zach 那么,它仍然是 KitKat 之前的一个问题,不是吗?
2021-03-15 17:41:54
loadUrl 当我尝试在输入字段中填写值时,也会导致软件键盘出现。
2021-03-17 17:41:54
@kami 添加到 Zach 答案,evaluateJavascript(),将异步运行 JavaScript。所以我们可以避免使用evaluateJavascript()阻塞UI线程。
2021-03-20 17:41:54
@kami loadUrl() 将重新加载页面并再次调用 onPageFinished()
2021-03-28 17:41:54
为什么使用evaluateJavascript() 而不是loadUrl()?
2021-04-04 17:41:54
public void run(final String scriptSrc) { 
        webView.post(new Runnable() {
            @Override
            public void run() { 
                webView.loadUrl("javascript:" + scriptSrc); 
            }
        }); 
    }
如果这不起作用,请执行 new Thread(new Runnaable(){..<like above>..}).start()
2021-03-17 17:41:54

我创建了一个很好的包装器来调用 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:

webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebViewInterface(), "AndroidErrorReporter");
这个功能,无论多么好的想法,都有错误的实现。当您查看生成的 js 调用时,这个调用:final Object a = new Object(); callJavaScript(mBrowser, "alert", 1, true, "abc", a);将屈服于SyntaxErrorUnexpected token这并不奇怪:javascript:try{alert(,,'abc',,)}catch(error){console.error(error.message);}
2021-03-10 17:41:54
即使是简单的调用也会callJavaScript(mBrowser, "alert", "abc", "def");产生错误,因为最后总是有流氓逗号。-1 从我。
2021-03-13 17:41:54
@Lukasz'Severiaan'Grela tnx,我解决了这个问题。PS 下次不要偷懒,你可以自己修复它......;)
2021-03-23 17:41:54
如果任何参数中包含 ' 字符,我想这将不起作用?例子:callJavascript(mBrowser, "can't do it");
2021-04-02 17:41:54
供将来参考:让我们保持积极的态度。指出代码中的错误并不是偷懒。它仍然是有用的反馈。
2021-04-08 17:41:54

是的,您有语法错误。如果您想在 logcat 中获取 Javascript 错误和打印语句,则必须onConsoleMessage(ConsoleMessage cm)在 WebChromeClient 中实现该方法。它提供了完整的堆栈跟踪,如 Web 控制台(检查元素)。这是方法。

public boolean onConsoleMessage(ConsoleMessage cm) 
    {
        Log.d("Message", cm.message() + " -- From line "
                             + cm.lineNumber() + " of "
                             + cm.sourceId() );
        return true;
    }

实施后,您将console.log在 logcat 上看到 Javascript 错误和打印语句 ( )。

是的,你是对的@MichaelLevy。谢谢你指出我那个错误。现在我已经编辑了我的答案。
2021-03-10 17:41:54
谢谢,您的回答正是我所需要的。我还建议人们在 WebChromeClient 中覆盖 onJsAlert()。在调试 webview 中托管的 Javascript 时,javascript 日志记录和警报的组合非常有用。
2021-03-13 17:41:54
我相信是在 WebChromeClient 而不是 WebViewClient 上。
2021-03-27 17:41:54