我试图调用一些javascript函数坐在运行在一个android webview内的html页面。下面的代码尝试做的很简单——从android应用程序,调用一个带有测试消息的javascript函数,该函数反过来调用一个java函数返回android应用程序,通过toast显示测试消息。
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();
}
}
我花了很多时间在谷歌上搜索,看看我哪里做错了。我找到的所有示例都使用了这种方法。有人发现问题了吗?
编辑:有其他几个外部javascript文件被引用和使用的html,他们会是问题吗?
修改@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;
}
}
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>
修改@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;
}
}