目前很多android app都内置了可以显示web页面的界面,会发现这个界面一般都是由一个叫做WebView的组件渲染出来的,学习该组件可以为你的app开发提升扩展性。

先说下WebView的一些优点:

  • 可以直接显示和渲染web页面,直接显示网页
  • webview可以直接用html文件(网络上或本地assets中)作布局
  • 和JavaScript交互调用

一、基本使用

首先layout中即为一个基本的简单控件:

<WebViewandroid:id="@+id/webView1"android:layout_width="fill_parent"android:layout_height="fill_parent"android:layout_marginTop="10dp" />

同时,因为要房访问网络,所以manifest中必须要加uses-permission:

<uses-permission android:name="android.permission.INTERNET"/>

在activity中即可获得webview的引用,同时load一个网址:

webview = (WebView) findViewById(R.id.webView1);
webview.loadUrl("http://www.baidu.com/");
//webview.reload();// reload page

这个时候发现一个问题,启动应用后,自动的打开了系统内置的浏览器,解决这个问题需要为webview设置 WebViewClient,并重写方法:

webview.setWebViewClient(new WebViewClient(){@Overridepublic boolean shouldOverrideUrlLoading(WebView view, String url) {view.loadUrl(url);return true;}});

若自己定义了一个页面加载进度的progressbar,需要展示给用户的时候,可以通过如下方式获取webview内页面的加载进度:

webview.setWebChromeClient(new WebChromeClient(){@Overridepublic void onProgressChanged(WebView view, int newProgress) {//get the newProgress and refresh progress bar}});

每个页面,都有一个标题,比如www.baidu.com这个页面的title即“百度一下,你就知道”,那么如何知道当前webview正在加载的页面的title呢:

webview.setWebChromeClient(new WebChromeClient(){@Overridepublic void onReceivedTitle(WebView view, String title) {titleview.setText(title);//a textview}});

二、通过webview控件下载文件

通常webview渲染的界面中含有可以下载文件的链接,点击该链接后,应该开始执行下载的操作并保存文件到本地中。webview来下载页面中的文件通常有两种方式:

1. 自己通过一个线程写java io的代码来下载和保存文件(可控性好)

2. 调用系统download的模块(代码简单)

方法一:

首先要写一个下载并保存文件的线程类

public class HttpThread extends Thread {private String mUrl;public HttpThread(String mUrl) {this.mUrl = mUrl;}@Overridepublic void run() {URL url;try {url = new URL(mUrl);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setDoInput(true);conn.setDoOutput(true);InputStream in = conn.getInputStream();File downloadFile;File sdFile;FileOutputStream out = null;if(Environment.getExternalStorageState().equals(Environment.MEDIA_UNMOUNTED)){downloadFile = Environment.getExternalStorageDirectory();sdFile = new File(downloadFile, "test.file");out = new FileOutputStream(sdFile);}//buffer 4kbyte[] buffer = new byte[1024 * 4];int len = 0;while((len = in.read(buffer)) != -1){if(out != null)out.write(buffer, 0, len);}//close resourceif(out != null)out.close();if(in != null){in.close();}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

随后要实现一个DownloadListener接口,这个接口实现方法OnDownloadStart(),当用户点击一个可以下载的链接时,该回调方法被调用同时传进来该链接的URL,随后即可以对该URL塞入HttpThread进行下载操作:

//创建DownloadListener (webkit包)
class MyDownloadListenter implements DownloadListener{@Overridepublic void onDownloadStart(String url, String userAgent,String contentDisposition, String mimetype, long contentLength) {System.out.println("url ==== >" + url);new HttpThread(url).start();}}
//给webview加入监听
webview.setDownloadListener(new MyDownloadListenter());

方法二:

直接发送一个action_view的intent即可:

class MyDownloadListenter implements DownloadListener{@Overridepublic void onDownloadStart(String url, String userAgent,String contentDisposition, String mimetype, long contentLength) {System.out.println("url ==== >" + url);//new HttpThread(url).start();Uri uri = Uri.parse(url);Intent intent = new Intent(Intent.ACTION_VIEW, uri);startActivity(intent);}}

三、错误处理

当我们使用浏览器的时候,通常因为加载的页面的服务器的各种原因导致各种出错的情况,最平常的比如404错误,通常情况下浏览器会提示一个错误提示页面。事实上这个错误提示页面是浏览器在加载了本地的一个页面,用来提示用户目前已经出错了。

但是当我们的app里面使用webview控件的时候遇到了诸如404这类的错误的时候,若也显示浏览器里面的那种错误提示页面就显得很丑陋了,那么这个时候我们的app就需要加载一个本地的错误提示页面,即webview如何加载一个本地的页面。

1. 首先我们需要些一个html文件,比如error_handle.html,这个文件里面就是当出错的时候需要展示给用户看的一个错误提示页面,尽量做的精美一些。然后将该文件放置到代码根目录的assets文件夹下。

2. 随后我们需要复写WebViewClient的onRecievedError方法,该方法传回了错误码,根据错误类型可以进行不同的错误分类处理

webview.setWebViewClient(new WebViewClient(){@Overridepublic void onReceivedError(WebView view, int errorCode,String description, String failingUrl) {switch(errorCode){case HttpStatus.SC_NOT_FOUND:view.loadUrl("file:///android_assets/error_handle.html");break;}}});

其实,当出错的时候,我们可以选择隐藏掉webview,而显示native的错误处理控件,这个时候只需要在onReceivedError里面显示出错误处理的native控件同时隐藏掉webview即可。

四、webview同步cookies

cookies是服务器用来保存每个客户的常用信息的,下次客户进入一个诸如登陆的页面时服务器会检测cookie信息,如果通过则直接进入登陆后的页面。

在webview中,如果之前已经登陆过了,那么下次再进入同样的登陆界面时,若需要再次登陆的话,一定会很恼人,所以这里提供一个webview同步cookies的方法。

1.首先,我们假设某个网站的登陆界面需要提供两个参数,一个是name,一个是pwd,那么要是对这个页面进行登陆,那么必须给与这两个信息。我们假设服务器已经注册了name为jason,pwd为123456这个账号。

2.下面,写一个Thread用来将name和pwd自动的登入,在服务器返回的response中获得cookie信息,稍后对这个cookie进行保存,这里先给出这个Thread的代码:

public class HttpCookie extends Thread {private Handler mHandler;public HttpCookie(Handler mHandler) {this.mHandler = mHandler;}@Overridepublic void run() {HttpClient client = new DefaultHttpClient();HttpPost post = new HttpPost("");//this place should add the login addressList<NameValuePair> list = new ArrayList<NameValuePair>();list.add(new BasicNameValuePair("name", "jason"));list.add(new BasicNameValuePair("pwd", "123456"));try {post.setEntity(new UrlEncodedFormEntity(list));HttpResponse reponse = client.execute(post);if(reponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){AbstractHttpClient absClient = (AbstractHttpClient) client;List<Cookie> cookies = absClient.getCookieStore().getCookies();for(Cookie cookie:cookies){if(cookie != null){//TODO//this place would get the cookies}}}} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (ClientProtocolException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

由于这是一个子线程,所以需要在主线程中创建并执行。

同时,因为其实子线程,那么里面必须含有一个handler的元素,用来当成功获取cookie后通知主线程进行同步和保存。初始化这个子线程的时候需要将主线程上的handler给传过来,随后在以上代码的TODO中发送消息,让主线程记录cookie,发送的这个消息需要将cookie信息包含进去:

if(cookie != null){//TODO//this place would get the cookiesMessage msg = new Message();msg.obj = cookie;if(mHandler != null){mHandler.sendMessage(msg);return;}
}

随后在主线程中(webview加载登陆界面前),在handler中将会获取到cookie信息,下面将对该cookie进行保存和同步:

private Handler mHandler = new Handler(){public void handleMessage(android.os.Message msg) {CookieSyncManager.createInstance(MainActivity.this);CookieManager cookieMgr = CookieManager.getInstance();cookieMgr.setAcceptCookie(true);cookieMgr.setCookie("", msg.obj.toString());// this place should add the login host address(not the login index address)CookieSyncManager.getInstance().sync();webview.loadUrl("");// login index address};};

这个时候发现webview加载的login index页面中可以自动的登陆了并显示登陆后的界面。

五、 WebView与JavaScript的交互

1. webview调用js

mWebView.loadUrl("javascript:do()");

以上是webview在调用js中的一个叫做do的方法,该js所在的html文件大致如下:

<html><script language="javascript">/* This function is invoked by the webview*/function do() {alert("1");}</script><body><a><div style="width:80px;margin:0px auto;padding:10px;text-align:center;border:2px solid #111111;" ><img id="droid" src="xx.png"/><br>Click me!</div></a></body>
</html>

2. js调用webview

我们假设下列的本地类是要给js调用的:

package com.test.webview;
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() {//TODO}});}}

首先给webview设置:

mWebview.setJavaScriptEnabled(true);

随后将本地的类(被js调用的)映射出去:

mWebView.addJavascriptInterface(new DemoJavaScriptInterface(), "demo");

“demo”这个名字就是公布出去给JS调用的,那么js久可以直接用下列代码调用本地的DemoJavaScriptInterface类中的方法了:

<body>  ...
</body>

六、WebView与JavaScript相互调用混淆问题

若webview中的js调用了本地的方法,正常情况下发布的debug包js调用的时候是没有问题的,但是通常发布商业版本的apk都是要经过混淆的步骤,这个时候会发现之前调用正常的js却无法正常调用本地方法了。

这是因为混淆的时候已经把本地的代码的引用给打乱了,导致js中的代码找不到本地的方法的地址。

解决这个问题很简单,即在proguard.cfg文件中加上一些代码,声明本地中被js调用的代码不被混淆。下面举例说明:

第五节中被js调用的那个类DemoJavaScriptInterface的包名为com.test.webview,那么就要在proguard.cfg文件中加入:

-keep public class com.test.webview.DemoJavaScriptInterface{public <methods>;
}

若是内部类,则大致写成如下形式:

-keep public class com.test.webview.DemoJavaScriptInterface$InnerClass{public <methods>;
}

若android版本比较新,可能还需要添加上下列代码:

-keepattributes *Annotation*
-keepattributes *JavascriptInterface*

来自:http://www.cnblogs.com/soaringEveryday/p/4495221.html

转载于:https://www.cnblogs.com/a446276468/p/5310270.html

Android WebView使用深入浅出相关推荐

  1. Android Webview历史高危漏洞与攻击面分析

    文章目录 前言 WebView基础 极简Demo程序 JS调用Android 加载远程HTML 接口攻击场景 漏洞示例程序 本地攻击程序 url白名单校验 代码执行漏洞 JAVA反射机制 历史漏洞PO ...

  2. Android WebView访问SSL证书网页(onReceivedSslError)

    Android WebView访问https SSL证书网页,如淘宝,需要在onReceivedSslError添加SSL支持 webview.setWebViewClient(new WebView ...

  3. android webview java_Android Webview中调用本地java方法

    在网页调用本地的分享SDK class JsObject { @JavascriptInterface public String toString() { return "injected ...

  4. android的webView的教程,Android WebView 应用界面开发教程

    WebView组件本身就是一个浏览器实现,Android5.0增强的WebView基于Chromium M37,直接支持WebRTC.WebAudio.WebGL.开发者可以直接在WebView中使用 ...

  5. Android WebView 支持H5图片上传input type=file

    2019独角兽企业重金招聘Python工程师标准>>> Android WebView 缓存处理 Android WebView 支持H5图片上传<input type=&qu ...

  6. Chrome 调试 Android WebView 网页

    手机开启开发者模式,并且Usb 连接到电脑 Android webView 开启调试模式 mWebView.setWebContentsDebuggingEnabled(true); Chrome 浏 ...

  7. Android webview 写入cookie的解决方法以及一些属性设置

    Android webview 写入cookie的解决方法以及一些属性设置 参考文章: (1)Android webview 写入cookie的解决方法以及一些属性设置 (2)https://www. ...

  8. android url webview,android - webview获取到当前页面的url

    android - webview获取到当前页面的url 2017-10-23 08:54 访问量: 2958 分类: 技术 使用 webview.getUrl() 即可. 可以完美返回  a.com ...

  9. Android Webview H5 秒开方案实现

    本文首发于微信公众号「玉刚说」 原文链接:Android Webview H5 秒开方案实现 前言 现在许多app都嵌入了H5页面, 然而WebView加载速度慢这个问题却一直影响着用户的体验, 所以 ...

最新文章

  1. 解决scrapy安装失败
  2. spring elasticsearch 按条件删除_Elasticsearch系列之Query DSL
  3. CentOS7.5常用命令整理
  4. 跟我学JAVA / 第三课:Java流程控制与数组
  5. Unity3d 游戏中集成Firebase 统计和Admob广告最新中文教程
  6. 集合的定义与并查操作(C语言)
  7. Python生成随机高斯模糊图片
  8. phpMyAdmin安装配置
  9. php对smarty的使用,[ php ] php smarty使用!
  10. redis、kafka、rabittMQ对比 (转)
  11. 湖南大学计算机与通信学院李燕,基于SVM的面部表情分析
  12. 合肥工业大学计算机与信息学院胡敏,合肥工业大学计算机与信息学院导师介绍:胡敏...
  13. Linux(Ubuntu)虚拟机识别U盘
  14. 百度飞桨(Python+AI)入门
  15. 计算机三级上机场,自学通过计算机二级、三级、四级,保研天津大学,证书拿到手软!你被中航大男神圈粉了吗?...
  16. pandas数据类型转为str
  17. 00_抓取猫眼电影排行TOP100
  18. 计算机休眠会断网,win10系统休眠断网的解决方法
  19. C#:DataGridView边框线、标题、单元格的各种颜色
  20. 兴安有礼隐私政策协议

热门文章

  1. 云存储之对象存储性价比小谈
  2. 2016全球十大主流ERP厂商“新鲜出炉”!
  3. ART、JIT、AOT、Dalvik之间有什么关系?
  4. 分区函数Partition By的与row_number()的用法以及与排序rank()的用法详解(获取分组(分区)中前几条记录)...
  5. phpeclipse+xdebug配置
  6. Iperf 源代码分析(四)
  7. TurboMail邮件服务器 V4.2.0 正式发布
  8. 数据结构预算法(六) 数组和矩阵(1)
  9. Linux装好MATLAB无法启动的解决办法
  10. matlab打开时总闪一下才打开_大家装窗帘轨道时,是不是多数都是下面这样的: 打开网易新闻 查看更多图片 或者做个窗帘盒,遮盖一下?...