WebView与JavaScript的交互总结
1、交互总结
WebView与JS之间的交互总结可以概括为下面两种:
- Android客户端去调用JS代码
- JS端去调用Android原生代码
它们之间互相调用的桥梁是WebView。
2、交互前准备
2.1 Android客户端代码
Activity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = findViewById(R.id.web_view);
//android调用JS代码的Button
btnAndroidCallJS = findViewById(R.id.btn_call_js);
//防止外部浏览器调用此链接
webView.setWebViewClient(new WebViewClient());
WebSettings settings = webView.getSettings();
//允许WebView使用JS
settings.setJavaScriptEnabled(true);
//支持通过JS打开新窗口(允许JS弹窗)
settings.setJavaScriptCanOpenWindowsAutomatically(true);
}
XML:
2.2 JS端代码
test.html:
这是JS调用原生1
这是JS调用原生2
这是JS调用原生3
3、Android端调用JS代码
3.1 Android端调用JS代码有2种方法:
- 通过WebView的
loadUrl()
- 通过WebView的
evaluateJavascript()
这两种方式调用JS代码时,格式都是以javascript:
开头的,后面接JavaScript的方法名。
3.2 通过WebView的loadUrl()
//Android调用JS代码
btnAndroidCallJS.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
webView.loadUrl("javascript:callJS()");
}
});
注意:JS代码调用一定要在WebViewClient
的onPageFinished()
回调之后才能调用,否则不会调用。
3.3 通过WebView的evaluateJavascript()
//Android调用JS代码
btnAndroidCallJS.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
webView.evaluateJavascript("javascript:callJS()", new ValueCallback() {
@Override
public void onReceiveValue(String s) {
//s是JS方法的返回值
Log.e("zw",s); //这里s是“Android调用了JS的callJS()”
}
});
}
});
这种方式比第一种方式效率高(执行时不会刷新页面),同时可以获取返回值。缺点是只兼容到Android4.4版本以后。
4、JS端调用Android端代码
3.1 JS端调用Android端代码有3种方法:
- 通过WebView的
addJavascriptInterface()
进行对象映射 - 通过
WebViewClient
的shouldOverrideUrlLoading()
方法回调拦截url - 通过
WebChromeClient
的onJsAlert()
、onJsConfirm()
、onJsPrompt()
方法回调拦截JS对话框alert()
、confirm()
、prompt()
消息
3.2 通过WebView的addJavascriptInterface()
进行对象映射
3.2.1 先定义一个和JS映射的对象
public class AndroidToJS {
// 定义JS需要调用的方法
// 被JS调用的方法必须加入@JavascriptInterface注解
@JavascriptInterface
public void callAndroid(String msg){
Log.e("zw","JS调用了Android的callAndroid(),msg : " + msg);
}
}
3.2.2 JavaScript内需要有Android调用原生的方法
//JS调用Android原生方法
function callAndroid(){
// 由于对象映射,所以调用android对象等于调用Android映射的对象
android.callAndroid("js调用了");
}
3.2.3 Android原生调用JavaScript方法
// 通过addJavascriptInterface()将Java对象映射到JS对象
//参数1:Javascript对象名
//参数2:Java对象名
webView.addJavascriptInterface(new AndroidToJS(),"android");
结果:
E/zw: JS调用了Android的callAndroid(),msg : js调用了
这种方法优点是使用简单,缺点是存在严重的漏洞问题,请看文章:你不知道的 Android WebView 使用漏洞
3.3 通过WebViewClient
的shouldOverrideUrlLoading()
方法回调拦截url
3.3.1 先约定好调用的URL协议
比如以js://webview?arg1=111
开头。
3.3.2 在JS中定义调用方法
//JS调用通过shouldOverrideUrlLoading()调用Android原生方法
function callAndroid2(){
//document.location代表当前页面的url
document.location = "js://webview?arg1=111&arg2=222"
}
3.3.3 Android端的WebView设置WebViewClient
对URL进行拦截
最好重写两个shouldOverrideUrlLoading()
方法,避免其中一个不生效。
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.e("ll", url );
if(url.startsWith("js")){
if(url.contains("webview")){
Toast.makeText(getApplicationContext(),"heihei",Toast.LENGTH_SHORT).show();
return true;
}
}
return super.shouldOverrideUrlLoading(view, url);
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Uri uri = request.getUrl();
Log.e("ll", uri.getScheme() + " , " + uri.getAuthority() + " , ");
if("js".equals(uri.getScheme())){
if("webview".equals(uri.getAuthority())){
Toast.makeText(getApplicationContext(),"heihei",Toast.LENGTH_SHORT).show();
return true;
}
}
return super.shouldOverrideUrlLoading(view, request);
}
});
3.4 通过WebChromeClient
的onJsAlert()
、onJsConfirm()
、onJsPrompt()
方法回调拦截JS对话框alert()
、confirm()
、prompt()
消息
关于WebChromeClient
的onJsAlert()
、onJsConfirm()
、onJsPrompt()
方法,可以在我的 WebView全面解析 这篇文章中得到解答。
由于alert()
没有返回值,confirm()
只能返回true
或者false
,而prompt()
可以返回任意类型的值,因此更加的灵活,这里,以prompt()
举例。
3.4.1 先约定好在prompt()
中显示信息的协议
比如以js://webview?arg1=111
开头。
3.4.2 在JS中定义调用方法
//JS调用通过prompt()调用Android原生方法
function callAndroid3(){
var result = prompt("js://webview?arg1=111");
alert(result);
}
3.4.3 Android端的WebView设置WebChromeClient
对传入的参数进行解析并返回
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
Log.e("ll",message + " , " + defaultValue);
if(message.startsWith("js")){
if(message.contains("webview")){
//confirm表示确认(并返回值),cancel表示取消。
result.confirm("8848");
//返回true表示不弹出系统提示框
return true;
}
}
return super.onJsPrompt(view,url,message,defaultValue,result);
}
5、总结
几种调用方式的优缺点总结如下:
6、参考资料
最全面总结 Android WebView与 JS 的交互方式