概述
今天来看看WebView和Js的交互功能如何实现
效果图
代码
首先我们需要准备一个html文件,放在assets目录中,方便我们从代码中加载,html的代码如下
<html>
<head>
<title>WebView和Js交互</title>
<script type="text/javascript">
function updateHtml(){
document.getElementById("content").innerHTML = "android调用了js的update方法";
}
</script>
</head>
<body>
<a onClick="window.android.showToast()" href="#">调用android方法</a><br/>
<span id="content"></span>
</body>
</html>
updateHtml方法是被Android调用的,用来更新当前页面的内容
a标签里我们指定了一个onClick属性,它的值是window.android.showToast(),其中android是我们定义的一个对象,通过下面的代码指定
webView.addJavascriptInterface(new JavaScriptInterface(),"android");
addJavaScriptInterface这个方法接收两个参数,第一个指定注入到JavaScript中的Java对象,第二个参数是这个参数的名字,通过window.name.methodName,我们就可以在js中调用android的方法了
showToast是我们在Android中定义的一个方法,Js调用
/**
* webview和js交互
*/
public class WebJsActivity extends AppCompatActivity {
private static final String TAG = "WebJsActivity";
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web_js);
webView = (WebView) findViewById(R.id.webview);
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl("file:///android_asset/demo.html");
webView.addJavascriptInterface(new JavaScriptInterface(),"android");
public void updateJs(View view) {
// webView.loadUrl("javascript:updateHtml()");//js方法无返回值
//有返回值处理
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript("javascript:updateHtml()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
System.out.println("==========" + value);
}
});
} else {
//19之前java调用js方法,js在调用java方法把返回值传过来
}
}
public class JavaScriptInterface{
@JavascriptInterface
public void showToast(){
Toast.makeText(WebJsActivity.this, "被JS调用了", Toast.LENGTH_SHORT).show();
}
}
}
这里我们注意到,Android中的方法加入了一个@JavascriptInterface注解,因为js可以通过反射调用我们的android代码,这样是有安全隐患的,谷歌为了安全,从API17开始,只有添加了这个注解的java方法才能够被js调用,那么API17以下我们想要实现交互,又不发生安全漏洞,要怎么做呢?其实js还有另一种方式调用android代码,
我们稍微修改下js的代码
<html>
<head>
<title>WebView和Js交互</title>
<script type="text/javascript">
function updateHtml(){
document.getElementById("content").innerHTML = "android调用了js的update方法";
return "success";
}
function callAndroid(){
document.location = "abc://webview?age=1&name=lxn";
}
</script>
</head>
<body>
<a onClick="callAndroid()" href="#">调用android方法</a><br/>
<span id="content"></span>
</body>
</html>
这里的主要修改是当我们在js中调用android方法是,不是直接去掉用定义好的某个方法,而是指定的一个协议,进行重定向,然后我们就可以在WebViewClient的shouldOverideUrlLoading方法中进行拦截处理的,代码如下
//WebChromeClient主要处理js的对话框
webView.setWebChromeClient(new WebChromeClient(){
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
return super.onJsAlert(view, url, message, result);
}
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
return super.onJsPrompt(view, url, message, defaultValue, result);
}
});
//WebViewClient主要处理各种通知,事件
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
checkUri(Uri.parse(url));
return true;
}
});
}
public void checkUri(Uri uri){
Log.d(TAG, "shouldOverrideUrlLoading: " + uri.getScheme());
Log.d(TAG, "shouldOverrideUrlLoading: " + uri.getAuthority());//webview
String age = uri.getQueryParameter("age");//1
String name = uri.getQueryParameter("name");//lxn
Log.d(TAG, "shouldOverrideUrlLoading: " + age +"--"+name);
if (uri.getScheme().equals("abc")) {
//这里调用android的方法
Toast.makeText(this, "通过url调用", Toast.LENGTH_SHORT).show();
}
}