Android WebView与JS交互全面详解(小结)
android 和 h5 都是移动开发应用的非常广泛。市面上很多app都是使用android开发的,但使用android来开发一些比较复杂附属类,提示性的页面是得不偿失的。而h5具有开发速度快,更新不用依赖于app的更新,只需要服务端更新相应的页面即可,所以,app和h5页面相结合就显得尤为重要。而android和h5都不可能每次都是独立存在的,而是相互影响也相互的调用,获取信息等,例如,h5页面要获取app中的用户的基本信息,或者app端要操作h5页面等,下面来看看这两是怎么交互的
目录
1. 交互方式总结
android与js通过webview互相调用方法,实际上是:
- android去调用js的代码
- js去调用android的代码
二者沟通的桥梁是webview
对于android调用js代码的方法有2种:
- 通过webview的loadurl()
- 通过webview的evaluatejavascript()
对于js调用android代码的方法有3种:
- 通过webview的addjavascriptinterface()进行对象映射
- 通过 webviewclient 的shouldoverrideurlloading ()方法回调拦截 url
- 通过 webchromeclient的onjsalert()、onjsconfirm()、onjsprompt()方法回调拦截js对话框alert()、confirm()、prompt()消息
2. 具体分析
2.1 android通过webview调用 js 代码
方式1:通过webview的loadurl()
实例介绍:点击android按钮,即调用webview js(文本名为javascript)中calljs()
具体使用:
步骤1:将需要调用的js代码以.html格式放到src/main/assets文件夹里
为了方便展示,本文是采用andorid调用本地js代码说明;
实际情况时,android更多的是调用远程js代码,即将加载的js代码路径改成url即可
需要加载js代码:javascript.html
// 文本名:javascript <!doctype html> <html> <head> <meta charset="utf-8"> <title>carson_ho</title> // js代码 <script> // android需要调用的方法 function calljs(){ alert("android调用了js的calljs方法"); } </script> </head> </html>
步骤2:在android里通过webview设置调用js代码
public class mainactivity extends appcompatactivity { webview mwebview; button button; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); mwebview =(webview) findviewbyid(r.id.webview); websettings websettings = mwebview.getsettings(); // 设置与js交互的权限 websettings.setjavascriptenabled(true); // 设置允许js弹窗 websettings.setjavascriptcanopenwindowsautomatically(true); // 先载入js代码 // 格式规定为:file:///android_asset/文件名.html mwebview.loadurl("file:///android_asset/javascript.html"); button = (button) findviewbyid(r.id.button); button.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { // 必须另开线程进行js方法调用(否则无法调用) mwebview.post(new runnable() { @override public void run() { // 注意调用的js方法名要对应上 // 调用javascript的calljs()方法 mwebview.loadurl("javascript:calljs()"); } }); } }); // 由于设置了弹窗检验调用结果,所以需要支持js对话框 // webview只是载体,内容的渲染需要使用webviewchromclient类去实现 // 通过设置webchromeclient对象处理javascript的对话框 //设置响应js 的alert()函数 mwebview.setwebchromeclient(new webchromeclient() { @override public boolean onjsalert(webview view, string url, string message, final jsresult result) { alertdialog.builder b = new alertdialog.builder(mainactivity.this); b.settitle("alert"); b.setmessage(message); b.setpositivebutton(android.r.string.ok, new dialoginterface.onclicklistener() { @override public void onclick(dialoginterface dialog, int which) { result.confirm(); } }); b.setcancelable(false); b.create().show(); return true; } }); } }
效果图
特别注意:js代码调用一定要在 onpagefinished() 回调之后才能调用,否则不会调用。
onpagefinished()属于webviewclient类的方法,主要在页面加载结束时调用
方式2:通过webview的evaluatejavascript()
优点:
- 该方法比第一种方法效率更高、使用更简洁。
- 因为该方法的执行不会使页面刷新,而第一种方法(loadurl )的执行则会。
android 4.4 后才可使用
具体使用
// 只需要将第一种方法的loadurl()换成下面该方法即可 mwebview.evaluatejavascript("javascript:calljs()", new valuecallback<string>() { @override public void onreceivevalue(string value) { //此处为 js 返回的结果 } }); }
2.1.2 方法对比
方式对比图
2.1.3 使用建议
两种方法混合使用,即android 4.4以下使用方法1,android 4.4以上方法2
// android版本变量 final int version = build.version.sdk_int; // 因为该方法在 android 4.4 版本才可使用,所以使用时需进行版本判断 if (version < 18) { mwebview.loadurl("javascript:calljs()"); } else { mwebview.evaluatejavascript("javascript:calljs()", new valuecallback<string>() { @override public void onreceivevalue(string value) { //此处为 js 返回的结果 } }); }
2.2 js通过webview调用 android 代码
2.2.1 方法分析
方式1:通过 webview的addjavascriptinterface()进行对象映射
步骤1:定义一个与js对象映射关系的android类:androidtojs
androidtojs.java(注释已经非常清楚)
// 继承自object类 public class androidtojs extends object { // 定义js需要调用的方法 // 被js调用的方法必须加入@javascriptinterface注解 @javascriptinterface public void hello(string msg) { system.out.println("js调用了android的hello方法"); } }
步骤2:将需要调用的js代码以.html格式放到src/main/assets文件夹里
需要加载js代码:javascript.html
<!doctype html> <html> <head> <meta charset="utf-8"> <title>carson</title> <script> function callandroid(){ // 由于对象映射,所以调用test对象等于调用android映射的对象 test.hello("js调用了android中的hello方法"); } </script> </head> <body> //点击按钮则调用callandroid函数 <button type="button" id="button1" onclick="callandroid()"></button> </body> </html>
步骤3:在android里通过webview设置android类与js代码的映射
public class mainactivity extends appcompatactivity { webview mwebview; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); mwebview = (webview) findviewbyid(r.id.webview); websettings websettings = mwebview.getsettings(); // 设置与js交互的权限 websettings.setjavascriptenabled(true); // 通过addjavascriptinterface()将java对象映射到js对象 //参数1:javascript对象名 //参数2:java对象名 mwebview.addjavascriptinterface(new androidtojs(), "test");//androidtojs类对象映射到js的test对象 // 加载js代码 // 格式规定为:file:///android_asset/文件名.html mwebview.loadurl("file:///android_asset/javascript.html");
特点
优点:使用简单,仅将android对象和js对象映射即可
缺点:存在严重的漏洞问题
方式2:通过 webviewclient 的方法shouldoverrideurlloading ()回调拦截 url
**具体原理: **
android通过 webviewclient 的回调方法shouldoverrideurlloading ()拦截 url解析该 url 的协议
如果检测到是预先约定好的协议,就调用相应方法
即js需要调用android的方法
具体使用:
步骤1:在js约定所需要的url协议
js代码:javascript.html
以.html格式放到src/main/assets文件夹里
<!doctype html> <html> <head> <meta charset="utf-8"> <title>carson_ho</title> <script> function callandroid(){ /*约定的url协议为:js://webview?arg1=111&arg2=222*/ document.location = "js://webview?arg1=111&arg2=222"; } </script> </head> <!-- 点击按钮则调用callandroid()方法 --> <body> <button type="button" id="button1" onclick="callandroid()">点击调用android代码</button> </body> </html>
当该js通过android的mwebview.loadurl("file:///android_asset/javascript.html")加载后,就会回调shouldoverrideurlloading (),接下来继续看步骤2:
public class mainactivity extends appcompatactivity { webview mwebview; // button button; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); mwebview = (webview) findviewbyid(r.id.webview); websettings websettings = mwebview.getsettings(); // 设置与js交互的权限 websettings.setjavascriptenabled(true); // 设置允许js弹窗 websettings.setjavascriptcanopenwindowsautomatically(true); // 步骤1:加载js代码 // 格式规定为:file:///android_asset/文件名.html mwebview.loadurl("file:///android_asset/javascript.html"); // 复写webviewclient类的shouldoverrideurlloading方法 mwebview.setwebviewclient(new webviewclient() { @override public boolean shouldoverrideurlloading(webview view, string url) { // 步骤2:根据协议的参数,判断是否是所需要的url // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数) //假定传入进来的 url = "js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的) uri uri = uri.parse(url); // 如果url的协议 = 预先约定的 js 协议 // 就解析往下解析参数 if ( uri.getscheme().equals("js")) { // 如果 authority = 预先约定协议里的 webview,即代表都符合约定的协议 // 所以拦截url,下面js开始调用android需要的方法 if (uri.getauthority().equals("webview")) { // 步骤3: // 执行js所需要调用的逻辑 system.out.println("js调用了android的方法"); // 可以在协议上带有参数并传递到android上 hashmap<string, string> params = new hashmap<>(); set<string> collection = uri.getqueryparameternames(); } return true; } return super.shouldoverrideurlloading(view, url); } } ); } }
特点
优点:不存在方式1的漏洞;
缺点:js获取android方法的返回值复杂。
如果js想要得到android方法的返回值,只能通过 webview 的 loadurl ()去执行 js 方法把返回值传递回去,相关的代码如下:
// android:mainactivity.java mwebview.loadurl("javascript:returnresult(" + result + ")"); // js:javascript.html function returnresult(result){ alert("result is" + result); }
方式3:通过 webchromeclient的onjsalert()、onjsconfirm()、onjsprompt()方法回调拦截js对话框alert()、confirm()、prompt() 消息
在js中,有三个常用的对话框方法:
常用的对话框方法
方式3的原理:android通过 webchromeclient 的onjsalert()、onjsconfirm()、onjsprompt()
方法回调分别拦截js对话框 (即上述三个方法),得到他们的消息内容,然后解析即可。
下面的例子将用拦截 js的输入框(即prompt()方法)
说明 :
常用的拦截是:拦截 js的输入框(即prompt()方法)
因为只有prompt()可以返回任意类型的值,操作最全面方便、更加灵活;而alert()对话框没有返回值;confirm()对话框只能返回两种状态(确定 / 取消)两个值
步骤1:加载js代码,如下: javascript.html
以.html格式放到src/main/assets文件夹里
<!doctype html> <html> <head> <meta charset="utf-8"> <title>carson_ho</title> <script> function clickprompt(){ // 调用prompt() var result=prompt("js://demo?arg1=111&arg2=222"); alert("demo " + result); } </script> </head> <!-- 点击按钮则调用clickprompt() --> <body> <button type="button" id="button1" onclick="clickprompt()">点击调用android代码</button> </body> </html>
当使用mwebview.loadurl("file:///android_asset/javascript.html")加载了上述js代码后,就会触发回调onjsprompt(),具体如下:
- 如果是拦截警告框(即alert()),则触发回调onjsalert();
- 如果是拦截确认框(即confirm()),则触发回调onjsconfirm();
步骤2:在android通过webchromeclient复写onjsprompt()
public class mainactivity extends appcompatactivity { webview mwebview; // button button; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); mwebview = (webview) findviewbyid(r.id.webview); websettings websettings = mwebview.getsettings(); // 设置与js交互的权限 websettings.setjavascriptenabled(true); // 设置允许js弹窗 websettings.setjavascriptcanopenwindowsautomatically(true); // 先加载js代码 // 格式规定为:file:///android_asset/文件名.html mwebview.loadurl("file:///android_asset/javascript.html"); mwebview.setwebchromeclient(new webchromeclient() { // 拦截输入框(原理同方式2) // 参数message:代表promt()的内容(不是url) // 参数result:代表输入框的返回值 @override public boolean onjsprompt(webview view, string url, string message, string defaultvalue, jspromptresult result) { // 根据协议的参数,判断是否是所需要的url(原理同方式2) // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数) //假定传入进来的 url = "js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的) uri uri = uri.parse(message); // 如果url的协议 = 预先约定的 js 协议 // 就解析往下解析参数 if ( uri.getscheme().equals("js")) { // 如果 authority = 预先约定协议里的 webview,即代表都符合约定的协议 // 所以拦截url,下面js开始调用android需要的方法 if (uri.getauthority().equals("webview")) { // // 执行js所需要调用的逻辑 system.out.println("js调用了android的方法"); // 可以在协议上带有参数并传递到android上 hashmap<string, string> params = new hashmap<>(); set<string> collection = uri.getqueryparameternames(); //参数result:代表消息框的返回值(输入值) result.confirm("js调用了android的方法成功啦"); } return true; } return super.onjsprompt(view, url, message, defaultvalue, result); } // 通过alert()和confirm()拦截的原理相同,此处不作过多讲述 // 拦截js的警告框 @override public boolean onjsalert(webview view, string url, string message, jsresult result) { return super.onjsalert(view, url, message, result); } // 拦截js的确认框 @override public boolean onjsconfirm(webview view, string url, string message, jsresult result) { return super.onjsconfirm(view, url, message, result); } }); } }
2.2.2 三种方式的对比 & 使用场景
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。