WebView中的Android调用JavaScript函数


249

我正在尝试调用一些javascript函数,这些函数位于.NET中html运行的页面中android webview。代码尝试在下面执行的操作非常简单-从android应用程序中,调用javascript带有测试消息的函数,然后依次在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!);" + "})()");

我确实启用javascriptWebView

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

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

编辑:中 还有其他一些外部javascript文件被引用和使用,这html可能是问题吗?


13
您尝试使用的代码在javascript端缺少引号。
Paul de Vrieze 2011年

2
请注意,自Android 4.2起@JavascriptInterface,您需要在要通过JavaScript接口提供给WebView的Java方法上使用装饰器。
2013年

1
从代码中myWebView.loadUrl("javascript:testEcho('Hello World!')");我了解到您已经将html文件附加到了该webview。你能告诉我你是怎么做到的吗?
Tony_craft 2014年

Answers:


195

我发现问题出在哪里:testEcho()参数中缺少引号。这是我接到电话的方式:

myWebView.loadUrl("javascript:testEcho('Hello World!')");


很好,但是如何将Java对象作为参数传递给JavaScript函数呢?
2013年

1
@KovácsImreString.Format(“ javascript:testEcho('%d','%d','%d')”,1,2,3); 我猜
user457015 2013年

谢谢,我也同时发现了。
科瓦奇斯Imre 2013年

1
从KitKat开始,有评估Java方法,请检查stackoverflow.com/a/32163655/3063226
Heitor,2016年

117

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

2
为什么使用评价Javascript()而不是loadUrl()?
Kamran Bigdely

2
@kami loadUrl()将重新加载页面并再次调用onPageFinished()
Zach

1
@Zach那时KitKat之前仍然是个问题,不是吗?
Vsevolod Ganin

2
@kami添加到Zach答案,valuateJavascript(),将异步运行JavaScript。因此,我们可以避免使用EvaluationJavascript()阻塞UI线程。
Prasad

loadUrl当我尝试在输入字段中填写值时,也会导致软件键盘显示出来。
约书亚

34
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()
Radu Simionescu

26

我创建了一个不错的包装器来调用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");

但是,此功能尽管很好,但实现错误。这一呼吁:final Object a = new Object(); callJavaScript(mBrowser, "alert", 1, true, "abc", a);将产生于SyntaxErrorUnexpected token这并不奇怪,当你将看到生成的JS调用:javascript:try{alert(,,'abc',,)}catch(error){console.error(error.message);}
卢卡斯“Severiaan”格雷拉

即使简单的调用也会callJavaScript(mBrowser, "alert", "abc", "def");产生错误,因为最后总是有流氓逗号。从我-1。
Lukasz'Severiaan'Grela 2015年

1
@ Lukasz'Severiaan'Grela tnx,我已解决该问题。PS下次不要偷懒,您可以自己修复...;)
Ilya Gazman

16
供将来参考:让我们保持乐观。指出代码中的错误并非易事。仍然是有用的反馈。
2015年

我想如果任何参数中有'字符,这将不起作用?示例:callJavascript(mBrowser, "can't do it");
Kostanos,

18

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

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

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


2
我相信是在WebChromeClient而不是WebViewClient上。
Michael Levy

是的,您是正确的@MichaelLevy。感谢您指出我的错误。现在,我已经编辑了答案。
Dinesh

1
谢谢,您的回答正是我所需要的。我还建议人们重写WebChromeClient中的onJsAlert()。调试Webview中托管的Javascript时,将javascript日志记录和警报结合起来会非常有用。
Michael Levy

13

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

谢谢。此方法会在任何变量内转义'字符吗?换句话说,它可以与:callJavascript(mBrowser, "can't do it");吗?
Kostanos

1
刚刚编辑了答案,并在'角色中添加了转义符
-Kostanos

2

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

MainActivity.java


import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import com.bluapp.androidview.R;

public class WebViewActivity3 extends AppCompatActivity {
    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_web_view3);
        webView = (WebView) findViewById(R.id.webView);
        webView.setWebViewClient(new WebViewClient());
        webView.getSettings().setJavaScriptEnabled(true);
        webView.loadUrl("file:///android_asset/webview1.html");


        webView.setWebViewClient(new WebViewClient(){
            public void onPageFinished(WebView view, String weburl){
                webView.loadUrl("javascript:testEcho('Javascript function in webview')");
            }
        });
    }
}

资产档案

<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>WebView1</title>
<meta forua="true" http-equiv="Cache-Control" content="max-age=0"/>
</head>

<body style="background-color:#212121">
<script type="text/javascript">
function testEcho(p1){
document.write(p1);
}
</script>
</body>

</html>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.