代码在Android Studio1.4, android的6.0的模拟器上测试没有问题,Android中的java方法和js方法互相调用,根据有参和无参,可以分为四种情况,以下逐一通过代码分析。java方法和js方法互相调用的前提是需要设置settings.setJavaScriptEnabled(true);
Android方法调用JavaScript,有参数
在js中定义方法jsWithArgs(arg),android方法需要调用该方法必须通过webview的loadurl方法,loadurl参数格式必须是javascript:jsWithArgs(\"" + "content" + "\")
其中jsWithArgs是js中定义的方法,且传入js方法的参数必须用双引号引起来
index_js.html
<html>
<script type="text/javascript">
function jsWithArgs(message) {
alert(message)
}
</script>
</html>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<Button android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:text="调用js方法" />
<WebView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/myWebView" />
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity {
private WebView myWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myWebView = (WebView) findViewById(R.id.myWebView);
Button btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
callJs(myWebView);
}
});
WebSettings settings = myWebView.getSettings();
settings.setJavaScriptEnabled(true);
myWebView.setWebChromeClient(new WebChromeClient() {});
myWebView.loadUrl("file:///android_asset/index_js.html");
}
private void callJs(WebView webView) {
String call1 = "javascript:jsWithArgs(\"" + "content" + "\")";
webView.loadUrl(call1);
}
}
Android方法调用JavaScript,无参数
android方法调用js方法没有参数情形相对简单,无须传参,直接置空。如js中声明 jsWithNoArgs()
,使用是"javascript:jsWithNoArgs()"
index_js.html
<html>
<script type="text/javascript">
function jsWithNoArgs() {
alert("Hello")
}
</script>
</html>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<Button android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:text="调用js方法" />
<WebView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/myWebView" />
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity {
private WebView myWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myWebView = (WebView) findViewById(R.id.myWebView);
Button btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
callJs(myWebView);
}
});
WebSettings settings = myWebView.getSettings();
settings.setJavaScriptEnabled(true);
myWebView.setWebChromeClient(new WebChromeClient() {});
myWebView.loadUrl("file:///android_asset/index_js.html");
}
private void callJs(WebView webView) {
String call1 = "javascript:jsWithNoArgs()";
webView.loadUrl(call1);
}
}
JavaScript调用Android方法,有参数
- js调用android方法需要添加
myWebView.addJavascriptInterface(new JsInteration(), "control");
,表示添加js接口,其中类JsInteration自己声明,”control”可以认为是该类的别名,并且在onCreate方法前声明@SuppressLint("JavascriptInterface")
。 - js调用android方法需要定义一个公共类,并且声明一个供js调用的方法,为了让api>17的系统也能调用,方法需要声明
@JavascriptInterface
。 - js中调用android方法格式为:
control.showToast('显示Toast')
,其中control就是类的别名,’显示Toast’是传给android方法的参数。
index_js.html
<html>
<input type="button" onclick="control.showToast('显示Toast')" value="点我出来一条消息" />
</html>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<WebView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/myWebView" />
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity {
private WebView myWebView;
@SuppressLint("JavascriptInterface")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myWebView = (WebView) findViewById(R.id.myWebView);
WebSettings settings = myWebView.getSettings();
settings.setJavaScriptEnabled(true);
myWebView.addJavascriptInterface(new JsInteration(), "control");
myWebView.setWebChromeClient(new WebChromeClient() {});
myWebView.loadUrl("file:///android_asset/index_js.html");
}
public class JsInteration {
@JavascriptInterface
public void showToast(String msg) {
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
}
}
JavaScript调用Android方法,无参数
index_js.html
<html>
<input type="button" onclick="control.jump()" value="点我打开新的activity" />
</html>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<WebView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/myWebView" />
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity {
private WebView myWebView;
@SuppressLint("JavascriptInterface")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myWebView = (WebView) findViewById(R.id.myWebView);
WebSettings settings = myWebView.getSettings();
settings.setJavaScriptEnabled(true);
myWebView.addJavascriptInterface(new JsInteration(), "control");
myWebView.setWebChromeClient(new WebChromeClient() {});
myWebView.loadUrl("file:///android_asset/index_js.html");
}
public class JsInteration {
@JavascriptInterface
public void jump(){
Handler handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
startActivity(new Intent(MainActivity.this, IntentActivity.class));
}
});
}
}
}
android方法调用js,而js调用android方法
这种情况跟android方法调用js类似,只是在js方法体中有一点不同:
<html>
<script type="text/javascript">
function toastMessage(message) {
window.control.toastMessage(message)
}
</script>
</html>
window是html中的组件,control就是在java文件中声明对象时指定的“别名“,toastMessage是自定义类中的方法名。有这种方法就可以在java中获取用户在html中输入的值。
android方法传递json给js,在webview显示
这种情况跟android方法调用js类似,只是在js方法体中有一点不同:
public class MyObject {
@JavascriptInterface
public void init() {
webView.post(new Runnable() {
@Override
public void run() {
//调用客户端setContactInfo方法
webView.loadUrl("javascript:setContactInfo('" + getJsonStr() + "')");
}
});
}
@JavascriptInterface
public String getJsonStr() {
try {
JSONObject object1 = new JSONObject();
object1.put("id", 1);
object1.put("name", "张三");
object1.put("phone", "123456");
JSONObject object2 = new JSONObject();
object2.put("id", 2);
object2.put("name", "李四");
object2.put("phone", "456789");
JSONArray jsonArray = new JSONArray();
jsonArray.put(object1);
jsonArray.put(object2);
return jsonArray.toString();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
<!DOCTYPE HTML>
<html>
<head>
<title></title>
<script type="text/javascript">
function showtext() {
var a = document.getElementById("text").value;
window.myObject.getHtmlInput(a)
alert(a)
}
//data数据类型为字符串,字符串里面是数组,每一个数组元素为一个json对象,例如"[{id:1,name:'张三',phone:'135656461'},{id:2,name:'李四',phone:'1896561'}]"
function setContactInfo(data) {
var tableObj = document.getElementById("contact");
var jsonObjects = eval(data); //通过eval方法处理得到json对象数组
for(var i=0; i<jsonObjects.length; i++) {
var jsonObj = jsonObjects[i]; //获取json对象
var tr = tableObj.insertRow(tableObj.rows.length); //添加一行
//添加三列
var td1 = tr.insertCell(0);
var td2 = tr.insertCell(1);
var td3 = tr.insertCell(2);
td1.innerHTML = jsonObj.id;
td2.innerHTML = jsonObj.name;
td3.innerHTML = jsonObj.phone;
}
}
</script>
</head>
<!--onload="javascript:myObject.init()调用服务器端init方法-->
<body onload="javascript:myObject.init()">
<input type="text" id="text" value="">
<input type="button" onclick="myObject.showtxt()" value="显示输入框内容"/>
<table id="contact">
<tr>
<td>编号</td>
<td>姓名</td>
<td>电话</td>
</tr>
</table>
</body>
</html>
通过上述代码就可以把java方法中的json字符串传递给js方法,并在webview中显示
可能会出现的问题
- 如果在自己定义的JsInteration类中的方法做如下操作:
@JavascriptInterface
public void jump(){
Handler handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
myWebView.loadUrl("javascript:jsWithNoArgs()");
}
});
}
则会出现这样的问题: java.lang.Throwable: A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread.
正确的方法是用myWebView替换上述方法体中的handler.
@JavascriptInterface
public void jump(){
myWebView.post(new Runnable() {
@Override
public void run() {
myWebView.loadUrl("javascript:jsWithNoArgs()");
}
});
}
在stackoverflow中也有同样的问题,详见:
http://stackoverflow.com/questions/22607657/webview-methods-on-same-thread-error
- 如果使用过程中不小心把“别名“写错,不会调用相应的方法,log日志则会有提示:
I/chromium: [INFO:CONSOLE(33)] "Uncaught ReferenceError: control is not defined", source: file:///android_asset/intent_js.html (33)
主意这个级别是info级别,所以最好不要把log级别调成error。