WebView如果作为简单的网页浏览器,对于一般的浏览行为来说,已经足够了。可做为企业开发者,你的App通常要嵌入自家公司的网页,如此一来,还得考虑App与Web之间的消息传递,这就涉及到App的原生代码与Web的JS代码之间的通信了。
App与Web做为消息通信的双方,具体的交互行为分为四类,包括:App通知Web执行某项动作、App主动从Web获取信息、Web通知App执行某项动作,Web主动从App获取信息,这四种行为详细说明如下:

1. App通知Web执行某项动作

Web提供一个JavaScript方法,然后App由WebView调用loadUrl加载该JS方法,具体的App代码如下所示:

     wv_js.loadUrl("javascript:showMsgFromWeb()");

该行为的执行效果如下图所示,App通知JS调用showMsgFromWeb方法,该方法弹出了一个alert消息框。

2. App主动从Web获取信息

WebView对象调用evaluateJavascript方法,该方法通过回调接口ValueCallback获得JS的返回串,具体的App代码如下所示:

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {// evaluateJavascript该方法为4.4以后引入wv_js.evaluateJavascript("getMsgFromWeb()", new ValueCallback<String>() {@Overridepublic void onReceiveValue(String value) {AlertDialog.Builder builder = new AlertDialog.Builder(WebScriptActivity.this);builder.setTitle("来自安卓的对话框").setMessage(UnicodeToString(value));builder.create().show();}});} else {Toast.makeText(this, " Android4.4之后才支持该功能", Toast.LENGTH_SHORT).show();}

该行为的执行效果如下图所示,App通知JS调用getMsgFromWeb方法,获得返回消息后再由App自行弹窗。

3. Web通知App执行某项动作

App需要定义一个专门给JS使用的类,并在该类中实现JS要调用的方法,具体的类代码如下所示:

 private final class Client {@JavascriptInterfacepublic void showMsgFromAndroid(String msg) {  //如要返回值可把void改为String等等类型AlertDialog.Builder builder = new AlertDialog.Builder(WebScriptActivity.this);builder.setTitle("来自安卓的对话框").setMessage(msg);builder.create().show();}@JavascriptInterfacepublic String getMsgFromAndroid(String msg) {return "这是Android返回的字符串:"+msg;}}

接着还要调用WebView对象的addJavascriptInterface方法,给这个新类注册一个实例名,然后JS才能通过该实例名调用App的方法。注册实例名的代码如下所示:

     wv_js.addJavascriptInterface(new Client(), "client");

该行为的执行效果如下图所示,Web调用App的showMsgFromAndroid方法,该方法弹出了一个AlertDialog。

4. Web主动从App获取信息

该行为的主要流程同行为三,区别在于App方法的返回值类型由void改为String,然后JS即可从App获得返回信息。
该行为的执行效果如下图所示,Web调用App的getMsgFromAndroid方法获得字符串,然后Web把该消息以alert方式弹窗。

下面是演示WebView与JavaScript交互用到的html文件源码:

<html>
<head>
<meta name="viewport" content="width=device-width, target-densitydpi=device-dpi" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript">function showMsgFromWeb(){alert("这是网页弹出的对话框");}function getMsgFromWeb(){return "这是网页返回的字符串";}function showMsgInAndroid(){var result = client.getMsgFromAndroid("这是网页给的参数");alert(result);}function showAndroidDialog(){client.showMsgFromAndroid("网页要求安卓弹窗");}
</script>
</head>
<body>
<font size='5'>测试js使用</font><br>
<button οnclick="javascript:showAndroidDialog()"><font size='5'>让android弹窗</font></button><br>
<button οnclick="javascript:showMsgInAndroid()"><font size='5'>调用Android方法获得字符串</font></button><br>
</body>
</html>

为了区分对话框是App来源的弹窗还是Web来源的弹窗,这里重写了WebChromeClient的onJsAlert方法,通过setTitle方法区分本次弹窗的来源途径。重写后的方法代码如下所示:

     public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {String title = mTitle;if (title==null || title.length()<=0) {title = "来自网页的对话框";}AlertDialog.Builder builder = new AlertDialog.Builder(WebScriptActivity.this).setTitle(title).setMessage(message).setPositiveButton("确定",new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {result.confirm();}});//setCancelable要设置为false,点击对话框外部时不让关闭对话框//不然JsResult的confirm方法没有得到执行,网页上的其它控件就不可使用builder.setCancelable(false).create().show();return true;}

另外还需注意WebView与JavaScript相互调用的几个要点:
1. WebView要调用setWebChromeClient方法设置JS的解释客户端,从而避免JS中alert方法不弹窗的问题,因为JS页面的渲染需要WebChromeClient去实现。
2. 如果JS调用App代码时报错“Uncaught TypeError: Object [object Object] has no method”,那是因为Android4.2以上版本默认不开放JS调用本地方法的权限,得给开放JS调用的方法加上“@JavascriptInterface”注释,该注释允许JS代码访问APP的指定方法。
3. evaluateJavascript是Android在4.4.2之后才引入的新方法,如果是4.4.2之前的Android版本,需要注意做兼容处理。
4. JS调用App方法,返回值中的中文是正常;但App获取JS方法,返回值的中文却是“\u”打头的字符串,所以要先将JS返回的字符串做转义处理,转义后的字符串才是App能够处理的正常汉字。
5. 如果App与JS存在嵌套调用(即A调用B,B内部又去调用A),那么Android4.4.2之后务必要保证两个调用在同一个线程中,不然运行时会报错“java.lang.Throwable: A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread.”。具体的解决方法是:调用WebView对象的post方法,然后在post的Runnable任务中再去调用JS方法,例子代码如下所示:

 private final class Contact {//网页的JS调用App的showcontacts方法,然后showcontacts内部又去调用JS的show方法@JavascriptInterfacepublic void showcontacts() {wv_local.post(new Runnable() {@Overridepublic void run() {wv_local.loadUrl("javascript:show()");}});}}

点此查看Android开发笔记的完整目录

Android开发笔记(一百五十一)WebView与JavaScript交互的四种形式相关推荐

  1. Android开发笔记(五十一)通过Messenger实现进程间通信

    进程间通信IPC IPC是"Inter-Process Communication"的缩写,即进程间通信.Android为APP提供了多进程工作模式,这是因为多线程存在若干局限: ...

  2. Android开发笔记(五十三)远程接口调用AIDL

    AIDL概述 AIDL全称是"Android Interface Definition Language",即Android的接口定义语言.AIDL用来协助开发者来处理进程间通信, ...

  3. Android开发笔记(六十一)文件下载管理DownloadManager

    下载管理DownloadManager 文件下载其实是网络数据访问的一种特殊形式,使用普通的http请求也能完成,就是实现起来会繁琐一些.因为下载功能比较常用,而且业务功能相对统一,所以从Androi ...

  4. Android开发笔记(五十四)数据共享接口ContentProvider

    ContentProvider 前面几节介绍了进程间通信的几种方式,包括消息包级别的Messenger.接口调用级别的AIDL.启动页面/服务级别的Notification,还有就是本节这个数据库级别 ...

  5. Android开发笔记(五十二)通知推送Notification

    PendingIntent 准备工作复习一下PendingIntent,前面的博文< Android开发笔记(五十)定时器AlarmManager>已经提到了它.PendingIntent ...

  6. Android开发笔记(五十七)录像录音与播放

    媒体录制MediaRecorder MediaRecorder是Android自带的录制工具,通过操纵摄像头和麦克风完成媒体录制,既可录制视频,也可单独录制音频.其中对摄像头Camera的介绍参见&l ...

  7. Android开发笔记(五十九)巧用传感器

    传感器Sensor 传感器是Android用来感知周围环境以及运动信息的工具.因为具体的感应信息依赖于相关硬件,所以虽然Android提供了众多的感应器,但不是每部手机都能支持这么多感应器,恰恰相反, ...

  8. Android开发笔记(八十一)屏幕规格适配

    Configuration 适配各种屏幕规格,首先要取到系统对于屏幕的配置信息,这些配置可从工具类Configuration获得.Configuration对象在Activity中通过调用getRes ...

  9. Android开发笔记(七十一)区分开发模式和上线模式

    为什么要区分两种模式 许多开发者(包括博主在内)都是闷骚的程序员,为了开发调试方便,常常在代码里加上日志,还经常在页面上各种弹窗提示.这固然有利于发现bug.提高软件质量,但过多的调试信息往往容易泄露 ...

最新文章

  1. python输入年份打印全年日历4×3_只需输入年份的打印日历
  2. python中sorted函数逆序_Python中sorted函数的用法(转)
  3. 沈阳建立通用航空产业基地,开辟国内首家无人机专用空域
  4. 2019年湘潭大学程序设计竞赛(重现赛)补题:F.Black White(尺取法)
  5. js实现浏览器后退页面刷新
  6. [数论]Gcd/ExGcd欧几里得学习笔记
  7. 还要做手机?罗永浩称还完债就重返科技行业
  8. ext拖动gridpanel的列组件消失_未来光伏组件市场格局:182mm市场占有率65%、210占5%、166占20%...
  9. 计算机网络-自顶向下方法(7th) 第二章 Review Questions 英文题目+中文答案
  10. express获取参数的几种方法
  11. uniapp 微信浏览器H5页面自定义分享链接
  12. java 常用的时间相关转化
  13. 学习太极创客 — ESP8226 (二)
  14. Oracle导入dmp文件步骤
  15. HDU 1422 重温世界杯 【C++练习题】
  16. 涨姿势|小众建模软件MakeHuman,人物角色建模基础入门教程(1)
  17. UART、RS232、RS485和RS422
  18. 问题xxx: TypeError: __randomstate_ctor() takes from 0 to 1 positional arguments but 2 were given
  19. excel学习09(笔记自用)
  20. 基于Flexsim的供应链建模与仿真课程设计

热门文章

  1. pytorch:属性统计
  2. 深度学习-吴恩达-笔记-3-浅层神经网络
  3. Python中np.sum()对axis的个人理解,超详细
  4. Mac安装prometheus+grafana监控
  5. 按键精灵post教程_【按键精灵教程】更为强大的HTTP方法
  6. android cygwin离线安装包,Cygwin配合NDK开发Android程序
  7. python找第二大的数索引_python – 在numpy数组中查找多个值的行索引
  8. 最快学习之Vue Route
  9. [Ext JS6]Sencha Cmd
  10. polycom安卓手机客户端_Spark,安卓上最好用的邮件客户端来了!附App下载