Android笔记之 Webview与Js交互-详情举例
Android调用网页自身Js
本地(asset)网页androidcalljs.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>android调用js</title>
<script>
function JsSelf(){
document.getElementById("demo").innerHTML="网页自身调用JS";
}
function JsUseEvaluateJavascript(){
document.getElementById("demo2").innerHTML="Android调用网页自身Js UseEvaluateJavascript";
return "Android调用网页自身Js UseEvaluateJavascript";
}
function JsUseLoadUrl(){
document.getElementById("demo1").innerHTML="Android调用网页自身Js UseLoadUrl";
}
</script>
</head>
<body>
<h1>android调用js</h1>
<p id="demo">网页调用js</p>
<p id="demo1">调用js loadUrl</p>
<p id="demo2">调用js useEvaluateJavascript</p>
<button type="button" onclick="JsSelf()">网页自身调用JS</button>
</body>
</html>
上面网页自身包含3个JavaScript函数
1、“loadUrl”调用网页自身js
String script = "javascript:JsUseLoadUrl()";
mWebView.loadUrl(script);
以上代码中JsUseLoadUrl()
对应的是网页自身JavaScript里面的function函数。
2、“evaluateJavascript”调用网页自身js
String script = "javascript:JsUseEvaluateJavascript()";
mWebView.evaluateJavascript(script, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
//value的值为 JavaScript执行 JsUseEvaluateJavascript()方法后的返回值
//即 “Android调用网页自身Js UseEvaluateJavascript”
Log.e(TAG,value);
}
});
同理,以上代码中JsUseEvaluateJavascript()
对应的是网页自身JavaScript里面的function函数。
这里注意的是“evaluateJavascript
”的参数列表,第一个参数是要执行的js,第二个则是Js函数执行后如果带有返回值,这里将在onReceiveValue
方法中接收该值,同时注意该值类型为String
。
3、区别
loadUrl
不带返回值,会刷新界面;
evaluateJavascript
带返回值,不会刷新界面,但需要API 19以后使用。
Android注入Js并调用
loadUrl
String script = "javascript:(function(){" +
"document.getElementById(\"demo1\").innerHTML=\"Android注入Js并调用 UseLoadUrl\";" +
"}())";
mWebView.loadUrl(script);
evaluateJavascript
String script = "javascript:(function(){" +
"document.getElementById(\"demo2\").innerHTML=\"Android调用外部Js useEvaluateJavascriptOut\";" +
"return \"Android调用外部Js useEvaluateJavascriptOut\";}())";
mWebView.evaluateJavascript(script, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
}
});
两种注入JS没有区别,需要注意的是注入的JavaScript格式:
"javascript:(function(){" +
//TODO 注意圆括号 花括号
"}())";
Js调用Android方法
JavaScript调用Android方法的HTML文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>js调用android</title>
<script>
function JsUseEvaluateJavascript(text){
document.getElementById("withparms").innerHTML="js调用android带参成功 android返回的值是:"+text;
return "Android调用Js UseEvaluateJavascript";
}
function JsUseLoadUrl(){
document.getElementById("noparm").innerHTML="js调用android方法成功 android调用js";
}
function callAndroidnoParms(){
android.callAndroidnoParms();
}
</script>
</head>
<body>
<h1>js调用android</h1>
<p id="withparms">等待android反馈</p>
<p id="noparm">等待android反馈</p>
<button type="button" onclick="callAndroidnoParms()">JS调用android方法</button>
<button type="button" onclick="window.android.callAndroidwithParms('我是参数')">JS带参数调用android方法
</button>
</body>
</html>
webview.addJavascriptInterface(object,String)
1、在Activity中的需要被调用的方法添加注解@JavascriptInterface
@JavascriptInterface
public void callAndroidnoParms() {
runOnUiThread(new Runnable() {
@Override
public void run() {
String script = "javascript:JsUseLoadUrl()";
mWebView.loadUrl(script);
}
});
}
上面方法callAndroidnoParms
是要被JavaScript调用的方法,调用成功之后,run
方法里面再从Android这边调用Js。
注意
上面调用callAndroidnoParms
成功之后,如果要对webview做其他操作,必须要和生成webview的线程在同一线程中,比如在主线程实例化的webview,这里就要使用runOnUiThread
,否则会报错(不会引起程序崩溃)
java.lang.RuntimeException: java.lang.Throwable: A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread. (Expected Looper Looper (main, tid 1) {4a7b4bb0} called on Looper (JavaBridge, tid 76) {4a7ba6d0}, FYI main Looper is Looper (main, tid 1) {4a7b4bb0})
2、mWebView.addJavascriptInterface(object, String);
使用addJavascriptInterface
方法,其中object
参数是映射成JavaScript
的对象,String
是给该映射对象取的别名。
比如 mWebView.addJavascriptInterface(this, "android");
该句话的意思就是把当前对象(Activity)映射成JavaScript的对象,android
就是对该映射对象取的别名,该别名在JavaScript调用Activity的方法会用到。
也可以自定义类来把需要调用的方法封装起来,其实和Activity差不多,只是在第一个参数那里有点区别,需要new。
public class JsCallAndroid {
@JavascriptInterface
public void callAndroidnoParms() {
runOnUiThread(new Runnable() {
@Override
public void run() {
String script = "javascript:JsUseLoadUrl()";
mWebView.loadUrl(script);
}
});
}
}
调用的时候:
mWebView.addJavascriptInterface(new JsCallAndroid(), "android");
3、JavaScript调用
<!--JavaScript标签里面的方法-->
function callAndroidnoParms(){
android.callAndroidnoParms();
}
<!--body标签里面的按钮-->
<button type="button" onclick="callAndroidnoParms()">JS调用android方法</button>
上面android.callAndroidnoParms()
意思就是执行android别名(Activity)里面的callAndroidnoParms()方法,也就是上面 第1点添加注解的那个方法。
还有一种方式就是
<!--body标签里面的按钮-->
<button type="button" onclick="window.android.callAndroidwithParms('我是参数')">JS带参数调用android方法
</button>
在Activity里面
@JavascriptInterface
public void callAndroidwithParms(final String text) {
runOnUiThread(new Runnable() {
@Override
public void run() {
//这里text的值=“我是参数” 即HTML网页里面传递过来的
String script = "javascript:JsUseEvaluateJavascript('" + text + "')";
//android调用js
mWebView.evaluateJavascript(script, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
//value的值=Android调用Js UseEvaluateJavascript
}
});
}
});
}
上面是调用带有参数的方法,使用的方式是window.android.callAndroidwithParms('我是参数')
。
当然上面调用不带参数的方法,即上面callAndroidnoParms
方法,也可以使用window.android.callAndroidnoParms()
方式
<button type="button" onclick="window.android.callAndroidnoParms()">JS调用android方法</button>
网上还有其他方式,即监听webview的某些方法,拦截处理,来实现android与js之间的交互,比如:shouldOverrideUrlLoading,onPageFinished,onProgressChanged,onJsAlert,onJsConfirm等等。
通常是在onProgressChanged或者onPageFinished方法里面注入js,修改原HTML的布局样式等。