JingBin's Home

Android-WebView与JS交互实例

纸上觉来终觉浅,绝知此事要躬行。 - 陆游/诗人(宋)

与js交互示例.jpg

正文

一切基于项目WebViewStudy来说明,都是最小单元案例,可作为参考研究,本文从几个方面来讲解:

  • 1、Java调用WebView里的js代码(传递参数)
  • 2、WebView里的js代码调用Java本地方法(传递参数)
  • 3、外部注入js代码
  • 4、WebView长按事件

相关JS代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<html>
<head>
<title>js调用android原生代码</title>
<meta http-equiv="Content-Type" content="text/html;charset=gb2312">
<meta id="viewport" name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,minimal-ui">
<script type="text/javascript">
function javacalljs(){
document.getElementById("content").innerHTML +=
"<br\>java调用了js函数,无参";
}
<!--这里取到的是 android端传过来的数据-->
function javacalljswithargs(data){
document.getElementById("content").innerHTML +=
("<br\>"+data);
}
</script>
</head>
<body>
<br/><br/>
<li><a onClick="window.injectedObject.startFunction()">点击调用java代码</a></li>
<!--可以将android端传过来的数据,处理后,放在这里再传给android端-->
<li><a onClick="window.injectedObject.startFunction('我是网页传出来的数据')">点击调用java代码并传递参数</a></li><br/>
<div id="content">内容显示</div>
</body>
</html>

Java调用WebView里的js代码(传递参数)

// 告诉WebView启用JavaScript执行。默认的是false。
ws.setJavaScriptEnabled(true);
1、如果点击调用就直接执行就好:

1
2
3
4
// 无参数调用
webView.loadUrl("javascript:javacalljs()");
// 传递参数调用
webView.loadUrl("javascript:javacalljswithargs('" + "android传入到网页里的数据,有参" + "')");

2、如果是显示后就调用,注意放在html显示完成之后
MyWebViewClient.java

1
2
3
4
5
6
7
8
@Override
public void onPageFinished(WebView view, String url) {
// 无参数调用
webView.loadUrl("javascript:javacalljs()");
// 传递参数调用
webView.loadUrl("javascript:javacalljswithargs('" + "android传入到网页里的数据,有参" + "')");
super.onPageFinished(view, url);
}

1
2
3
4
5
6
7
8
9
10
/**
* 4.4以上可用 evaluateJavascript 效率高
*/
private void load(String jsCode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
evaluateJavascript(jsCode, null);
} else {
loadUrl(jsCode);
}
}

WebView里的js代码调用Java本地方法(传递参数)

这里有一个js点击方法:

1
2
<li><a onClick="window.injectedObject.startFunction()">点击调用java代码</a></li>
<li><a onClick="window.injectedObject.startFunction('我是网页传出来的数据')">点击调用java代码并传递参数</a></li>

实现与js交互接口:

1
webView.addJavascriptInterface(new MyJavascriptInterface(this), "injectedObject");

这里的”injectedObject”对应js里的”window.injectedObject.startFunction()”,其中MyJavascriptInterface.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
* Created by jingbin on 2016/11/17.
* js通信接口
*/
public class MyJavascriptInterface {
private Context context;
public MyJavascriptInterface(Context context) {
this.context = context;
}
/**
* 前端代码嵌入js:
* imageClick 名应和js函数方法名一致
*
* @param src 图片的链接
*/
@JavascriptInterface
public void imageClick(String src) {
Log.e("imageClick", "----点击了图片");
Log.e("src", src);
}
/**
* 前端代码嵌入js
* 遍历<li>节点
*
* @param type <li>节点下type属性的值
* @param item_pk item_pk属性的值
*/
@JavascriptInterface
public void textClick(String type, String item_pk) {
if (!TextUtils.isEmpty(type) && !TextUtils.isEmpty(item_pk)) {
Log.e("textClick", "----点击了文字");
Log.e("type", type);
Log.e("item_pk", item_pk);
}
}
/**
* 网页使用的js,方法无参数
*/
@JavascriptInterface
public void startFunction() {
Log.e("startFunction", "----无参");
}
/**
* 网页使用的js,方法有参数,且参数名为data
*
* @param data 网页js里的参数名
*/
@JavascriptInterface
public void startFunction(String data) {
Log.e("startFunction", "----有参" + data);
}
}

且对标里面的两个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 网页使用的js,方法无参数
*/
@JavascriptInterface
public void startFunction() {
Log.e("startFunction", "----无参");
}
/**
* 网页使用的js,方法有参数,且参数名为data
*
* @param data 网页js里的参数名
*/
@JavascriptInterface
public void startFunction(String data) {
Log.e("startFunction", "----有参" + data);
}

外部注入js代码

有时候我们得到一个网页,这个网页并不是我们订制的,里面没有我们调用的js代码,这时候我们可在前端直接注入js的。
比如 网页里面有图片,我们点击图片想要查看图片和保存图片到本地,这时候网页并没有实现这个js方法供我们调用,但是我们可以注入js代码,来实现这个需求。

在html加载完成之后,我们调用这段js:

1
2
3
4
5
6
7
8
// 这段js函数的功能就是,遍历所有的img节点,并添加onclick函数,函数的功能是在图片点击的时候调用本地java接口并传递url过去
webView.loadUrl("javascript:(function(){" +
"var objs = document.getElementsByTagName(\"img\");" +
"for(var i=0;i<objs.length;i++)" +
"{" +
"objs[i].onclick=function(){window.injectedObject.imageClick(this.getAttribute(\"src\"));}" +
"}" +
"})()");

这时候再看MyJavascriptInterface.java里的imageClick方法:

1
2
3
4
5
6
7
8
9
10
11
/**
* 前端代码嵌入js:
* imageClick 名应和js函数方法名一致
*
* @param src 图片的链接
*/
@JavascriptInterface
public void imageClick(String src) {
Log.e("imageClick", "----点击了图片");
Log.e("src", src);
}

src即为图片链接,可以作为显示和下载用。

WebView长按事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
webView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
final WebView.HitTestResult hitTestResult = webView.getHitTestResult();
// 如果是图片类型或者是带有图片链接的类型
if (hitTestResult.getType() == WebView.HitTestResult.IMAGE_TYPE ||
hitTestResult.getType() == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
// 弹出保存图片的对话框
new AlertDialog.Builder(WebViewActivity.this)
.setItems(new String[]{"查看大图", "保存图片到相册"}, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String picUrl = hitTestResult.getExtra();
//获取图片
Log.e("picUrl", picUrl);
switch (which) {
case 0:
break;
case 1:
break;
default:
break;
}
}
})
.show();
return true;
}
return false;
}
});

参考资料