近日苹果研发(北京)有限公司成立。该公司注册资本1亿元人民币,投资总额3亿元人民币,共有员工约500人。公司位于中关村朝阳园,靠近地铁14号线东湖渠站。未来
致力于计算机软硬件、通讯、音频和视频设备、消费电子产品技术及信息技术等先进技术的研发,同时
加强与本地合作伙伴和高校的关系,支持全国范围内的人才发展。
明天就是国庆啦,先提前祝大家节日快乐,当然也祝我们的祖国生日快乐。国庆期间我就不推送文章了,放假回来之后将会给大家带来一个大惊喜,敬请期待。
本篇来自
姜维
的投稿,要是经常跟WebView打交道的朋友,那么对于今天的话题肯定不会陌生。本篇将从三个角度出发,带你找到最优方案。
姜维
的博客地址:http://blog.csdn.net/jiangwei0910410003
最近在开发过程中遇到一个问题,就是
WebView
使用的时候,还是需要解决之前系统(4.2之前)导致的一个漏洞,虽然现在这个系统版本用户很少了,但是也不能忽视,关于这个漏洞,这里就不多做解释了,可能有的同学早就了解了,本来想写一篇文章详细介绍一下,但是网上的知识太多了,而且都很详细,就没弄了,这里大致简单明了的说几句:
这个漏洞导致的原因主要是因为Android中
WebView
中的
JS访问本地方法
的方式存在缺陷,我们做过交互的都知道,Android中的交互方式是通过
WebView
的一个方法:
addJavascriptInterface(new JSObject(), "myObj");
第一个参数:
Android本地对象;
第二个参数:
JS代码中需要使用的对象。
所以这里看其实就相当于一个映射关系,把Android中的本地对象和JS中的对象关联即可。
那么这里就存在这样的一个问题了,
在4.2系统之前
,JS中通过对象调用的方法无需任何注解约束,那么就意味着JS中拿到这个对象,就可以调用这个对象中所有的方法。
而我们知道Android中的对象有一个公共的方法
getClass()
方法,而这个方法可以获取到当前类 类型Class,而这个类型有一个很关键的方法就是
Class.forName
,这个方法可以加载一个类,这里可以加载
java.lang.Runtime
这个类,而这个类就可以执行本地命令了,那么就会发生危险了,比如这里可以执行命令获取本地设备的SD卡中的文件等信息,非常危险的。
上面可能说的还是有些同学不太了解,
下面
就用一段简单的JS代码来了解一下:
看到这段JS之后的同学应该好理解了,因为我们Android本地通过
WebView
进行了对象映射,那么
WebView
加载页面中如果包含这段JS代码,那么就会存在这个问题,这里先遍历window中所有的对象,然后查找这个对象是否有
getClass方法
,有的话就在利用反射调用
Runtime类
执行具体命令即可。其实这个漏洞也得力于JS中的语法特性,这里可以看到JS语法非常的灵活。
当然对于 Android4.2 之后系统修复了这个漏洞,修复方法也很简单,加上注解约束:
@JavascriptInterface
就是只有加上这个注解的方法才会被JS调用,那么我们知道
getClass
是
Object类
中的,肯定没有这个注解,那么上面的JS代码肯定执行不到了。就这样解决了这个漏洞。
还有一个问题,就是Android系统默
认的会给
WebView
添加一个JS映射对象:
searchBoxJavaBridge_
这个对象是 Android3.0 之后默认加上去的,也就是说通过这个对象也是可以操作的上面的代码的。
说完了,这个漏洞,下面开始说今天的正题了,为什么要先介绍这个漏洞呢?原因就是如果要在
4.2以下版本
中解决这个漏洞的话就需要借助今天介绍的内容了,首先来看看今天的内容主要是介绍
Android 中 WebView的JS 和 本地交互 的三种方式
:
第一种方式:通过addJavascriptInterface方法进行添加对象映射
这种方式不多解释了,也是Android中最常用的方式,但是这种方式会存在风险就是上面说到的漏洞问题。
这里定义一个简单的本地对象,在需要被调用的方法加上约束注解。JS代码也很简单:
这种方式的好处在于使用简单明了,本地和JS的约定也很简单,就是对象名称和方法名称约定好即可,缺点就是存在漏洞问题。
第二种方式:利用WebViewClient接口回调方法拦截url
这种方式其实实现也很简单,就是我们可以添加
WebViewClient
回调接口,在
shouldOverrideUrlLoading
回调方法中拦截url,然后解析这个url的协议,如果发现是我们约定好的协议就开始解析参数执行具体逻辑:
代码也很简单,这个方法可以拦截
WebView
中加载url的过程,得到对应的url,我们就可以通过这个方法,和网页JS约定好一个协议,看一下JS代码:
这个JS代码执行之后,就会触发本地的
shouldOverrideUrlLoading
方法,然后进行参数解析,调用指定方法。
这个方法是不会存在第一种方法的漏洞问题,但是细心的同学可以发现,这里本地和JS之间的约定有点繁琐,比如要约定好协议,参数名称等信息,没有第一种方式方便。而且最主要的问题是,这个只能主动的调用本地化方法,如果想得到方法的返回值,只能通过
WebView
的
loadUrl
方法去执行JS方法,把返回值传递回去:
mWebView.loadUrl("javascript:clicktworesult("+res+")")
;
看到这种方式是非常繁琐的。在Android中也是不提倡使用的。
注意:
在 iOS 中没有像 Android 中的第一种方式,他也是为了安全考虑,所以 iOS 中的交互就是采用的第二种方式,通过 拦截url 来进行操作的。
第三种方式:利用WebChromeClient回调接口的三个方法拦截消息
这个方法的原理其实和第二种方式差不多,只是拦截的接口方法不一样:
Android中的
WebView
添加
WebChromeClient
接口,可以拦截JS中的几个提示方法,也就是几种样式的对话框,在JS中有三个常用的对话框方法: