本文作者kymjs张涛,沪江教育Android开发工程师,《KJFrameForAndroid》开发框架作者。爱看书,爱敲码,善于交流,乐于分享。个人博客地址:http://kymjs.com/

摘要

作为Android开发者,我们都知道在手机中内置了一款高性能 webkit 内核浏览器,在 SDK 中封装为一个叫做 WebView 组件。今天就为大家讲讲Android中WebView的详细使用方法。

作为Android开发者,我们都知道在手机中内置了一款高性能 webkit 内核浏览器,在 SDK 中封装为一个叫做 WebView 组件。

在开发过程中应该注意几点:

1.这是最基本的 AndroidManifest.xml 中必须添加访问网络权限。
2.如果访问的页面中有 Javascript,则 WebView 必须设置支持 Javascript。

WebView.getSettings().setJavaScriptEnabled(true);

3.如果页面中链接,如果希望点击链接继续在当前browser中响应,而不是新开Android的系统browser中响应该链接,必须覆盖 WebView的WebViewClient对象。

mWebView.setWebViewClient(new WebViewClient(){public boolean shouldOverrideUrlLoading(WebView view, String url){ view.loadUrl(url);return true;}
});

4.如果不做任何处理 ,浏览网页,点击系统“Back”键,整个 Browser 会调用 finish()而结束自身,如果希望浏览的网页回退而不是推出浏览器,需要在当前Activity中处理并消费掉该 Back 事件.(代码有些精简)

public boolean onKeyDown(int keyCode, KeyEvent event) {if ((keyCode == KEYCODE_BACK) && mWebView.canGoBack()) { mWebView.goBack();return true;}return super.onKeyDown(keyCode, event);
}

与js互调

既然可以显示网页,那么当然也可以让网页操作本地方法。(由于一行写不下,缩进我调整了一下)

public class WebViewDemo extends Activity { private WebView mWebView;private Handler mHandler = new Handler(); public void onCreate(Bundle icicle) { setContentView(R.layout.WebViewdemo);mWebView = (WebView) findViewById(R.id.WebView); WebSettings webSettings = mWebView.getSettings(); webSettings.setJavaScriptEnabled(true); mWebView.addJavascriptInterface(new Object() {public void clickOnAndroid() {mHandler.post(new Runnable() {public void run() { mWebView.loadUrl("javascript:wave()");}});}}, "demo"); mWebView.loadUrl("file:///android_asset/demo.html"); }
}

我们看 addJavascriptInterface(Object obj,String interfaceName)这个方法 ,该方法将一个java对象绑定到一个javascript对象中,javascript对象名就是 interfaceName(demo),作用域是Global.这样初始化 WebView 后,在WebView加载的页面中就可以直接通过javascript:window.demo访问到绑定的java对象了. 来看看在html中是怎样调用的.

<html>
<script language="javascript">function wave() {document.getElementById("droid").src="android_waving.png";}
</script>
<body><a onClick="window.demo.clickOnAndroid()"><img id="droid" src="android_normal.png" mce_src="android_normal.png"/><br> Click me! </a>
</body>
</html>

这样在 javascript 中就可以调用 java 对象的 clickOnAndroid()方法了,同样我们可以在此对象中定义很多方法(比如发短信,调用联系人列表等手机系统功能),这里 wave()方法是 java 中调用 javascript 的例子.

需要说明一点:addJavascriptInterface方法中要绑定的Java对象及方法要运行另外的线程中,不能运行在构造他的线程中,这也是使用 Handler 的目的.

深入使用WebView

让js调用Android代码

首先简述 WebView、WebViewClient、WebChromeClient 之间的区别:
在 WebView 的设计中,不是什么事都要 WebView类干的,有些杂事是分给其他人的,这样 WebView 专心干好 自己的解析、渲染工作就行了.WebViewClient 就是帮助 WebView 处理各种通知、请求事件等 ,WebChromeClient 是辅助 WebView 处理 Javascript 的对话框,网站图标,网站 title.

功能实现:

利用 android 中的 WebView 加载一个 html 网页,在 html 网页中定义一个按钮,点击按钮弹出一 个 toast.

实现步骤:

首先定义一个接口类,将上下文对象传进去,在接口类中定义要在 js 中实现的方法。
接着在assets资源包下定义一个 html 文件,在文件中定义一个 button.button 的点击事件定义为一个 js 函数.

之后在 xml 中定义一个 WebView 组件,在活动类中获取 WebView 并对 WebView 参数进行设置,此处特别注意要设置 WebView 支持 js 且将定义的 js 接口类添加到 WebView 中去,此后在 js 中就可以利用该接口类中定义的 函数了.即:

myWebView.getSettings().setJavaScriptEnabled(true);myWebView.addJavascriptInterface(new JavaScriptinterface(this),”android”);

最后利用 WebView 加载本地 html 文件的方法是:

myWebView.loadData(htmlText,"text/html", "utf-8");

此处的htmltext 是以字符串的方式读取 assets 报下 html中的内容.

4.实现利用返回键返回到上一页:

设置 WebView 的按键监听,监听到期返回键并判断网页是否能够返回 ,利用 WebView 的 goBack()返回到上一页.

WebView 缓存

在项目中如果使用到 WebView 控件,当加载 html 页面时,会在/data/data/包名目录下生成 database 与 cache 两个文件夹(我的手机没有root,就不截图了)。

请求的 url 记录是保存在 WebViewCache.db,而 url 的内容是保存在 WebViewCache 文件夹下. 大家可以自己动手试一下,定义一个html文件,在里面显示一张图片,用WebView加载出来,然后再试着从缓存里把这张图片读取出来并显示 。

WebView 删除缓存

其实已经知道缓存保存的位置了,那么删除就很简单了,获取到这个缓存,然后删掉他就好了。

//删除保存于手机上的缓存
private int clearCacheFolder(File dir,long numDays) { int deletedFiles = 0;if (dir!= null && dir.isDirectory()){try {for (File child:dir.listFiles()){if (child.isDirectory()) {deletedFiles += clearCacheFolder(child, numDays);}if (child.lastModified() < numDays) {if (child.delete()) {deletedFiles++; }}}} catch(Exception e) {e.printStackTrace(); }}return deletedFiles;
}

是否启用缓存功能也是可以控制的

//优先使用缓存: WebView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //不使用缓存: WebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);

在退出应用的时候加上如下代码,可以完整的清空缓存

File file = CacheManager.getCacheFileBaseDir();if (file != null && file.exists() && file.isDirectory()) {for (File item : file.listFiles()) {item.delete();}file.delete();}context.deleteDatabase("WebView.db"); context.deleteDatabase("WebViewCache.db");

WebView 处理 404 错误

显示网页还会遇到一个问题,就是网页有可能会找不到,WebView当然也是可以处理的(代码如果全部贴出来实在太多了,这里就只贴重要部分了)

public class WebView_404 extends Activity { private Handler handler = new Handler() {public void handleMessage(Message msg) {if(msg.what==404) {//主页不存在//载入本地 assets 文件夹下面的错误提示页面 404.html web.loadUrl("file:///android_asset/404.html");}else{web.loadUrl(HOMEPAGE);}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {web.setWebViewClient(new WebViewClient() {public boolean shouldOverrideUrl(WebView view,String url) { if(url.startsWith("http://") && getRespStatus(url)==404) {view.stopLoading();//载入本地 assets 文件夹下面的错误提示页面 404.html view.loadUrl("file:///android_asset/404.html");}else{view.loadUrl(url);}return true;}});new Thread(new Runnable() {public void run() {Message msg = new Message();//此处判断主页是否存在,因为主页是通过 loadUrl 加载的,//此时不会执行 shouldOverrideUrlLoading 进行页面是否存在的判断 //进入主页后,点主页里面的链接,链接到其他页面就一定会执行shouldOverrideUrlLoading 方法了 if(getRespStatus(HOMEPAGE)==404) {msg.what = 404;}handler.sendMessage(msg);}).start();}
}

判断 WebView 是否已经滚动到页面底端

在View中有一个getScrollY()方法,可以返回当前可见区域的顶端距整个页面顶端的距离,也就是当前内容滚动的距离。

还有getHeight()或者 getBottom()方法都返回当前 View 这个容器的高度
在ViewView中还有getContentHeight() 方法可以返回整个 html 页面的高度,但并不等同于当前整个页面的高度 ,因为 WebView 有缩放功能。你可以通过如下代码来启动或关闭webview的缩放功能。

mWebView.getSettings().setSupportZoom(true);
mWebView.getSettings().setBuiltInZoomControls(true);

所以当前整个页面的高度实际上应该是原始 html 的高度再乘上缩放比例. 因此,更正后的结果 ,准确的判断方法应该是:

// 如果已经处于底端
if(WebView.getContentHeight*WebView.getScale() -(webvi ew.getHeight()+WebView.getScrollY())){ //XXX
}

WebView获取服务器中的 session 问题

接下来我们讲如下两个问题:

  1. Android 中的 WebView 如何获取服务器页面的 jsessionid 的值
  2. Android 的 WebView 又是如何把得到的 jsessionid 的值在 set 到服务器中,一致达到他们在同一个 jsessionid 的回话中.

其实非常非常简单,只不过是几个方法罢了:

CookieManager cm = CookieManager.getInstance();
cm.removeAllCookie();
cm.getCookie(url);
cm.setCookie(url, cookie);

另外还有个 CookieSyncManager,也许你会在一些旧的项目中看到它。从名字来理解,它实际上应该是一个异步缓存器。不过我们看到这个方法已经被标记为过时了,查看源码可以看到过时原因是现在WebView已经是自动的异步缓存了,所以这个类已经没有存在的意义了。 CookieSyncManager

WebView清除本地cookies

首先,要清除肯定要会添加,这里给大家提供一个工具方法:

/**** 如果用户已经登录,则同步本地的cookie到webview中*/public void synCookies() {if (!CacheUtils.isLogin(this)) return;CookieSyncManager.createInstance(this);CookieManager cookieManager = CookieManager.getInstance();cookieManager.setAcceptCookie(true);cookieManager.removeSessionCookie();//移除String cookies = PreferenceHelper.readString(this, AppConfig.COOKIE_KEY, AppConfig.COOKIE_KEY);KJLoger.debug(cookies);cookieManager.setCookie(url, cookies);CookieSyncManager.getInstance().sync();}

在使用网页版淘宝或百度登录时,WebView会自动登录上次的帐号!(因为WebView 记录了帐号和密码的cookies) 所以,需要清除 SessionCookie也是有必要的。
那么CookieManager同样也为我们提供了清除cookie的方法

CookieManager.getInstance().removeSessionCookie();

这里顺便说一下WebView本身也是会记录html缓存的,上一篇博客中我讲了一种通过文件操作去清理缓存的方法,后来我又发现,其实webview本身就提供了清理缓存的方法,其中参数true是指是否包括磁盘文件也一并清除,传true就和我们昨天的讲的效果是一样的了:

webview.clearCache(true);
webview.clearHistory();

讲一个案例

讲了这么多的理论知识,最后讲一个使用案例。WebView在实际使用中可以分为两种使用方法,第一种就是类似于QQ微信那种,使用loadUrl直接去显示一个链接,这种方式太简单了,传一个url就行,我就不多说了。

那么需要详细讲的是第二种,类似的实现大家可以看看开源中国客户端,网易新闻客户端,爱看博客,等客户端的实现方式,它们实际上也是通过webview来显示的一个网页内容,但是并不是单纯的loadurl,而是以字符串的形式去加载一个已经获取到了的html源代码。这样做的好处在于显示的页面可以完全的根据自己喜好来定义,比如我想在末尾添加一张图片,那么简单,在这个html字符串的末尾插入一个img标签就可了。至于使用方法,其实我们在上一篇博客的时候有提到过:

myWebView.loadData(htmlText,”text/html”, “utf-8”);

其中htmltext就是我们需要加载的html字符串,使用这个方法可以直接将这个字符串作为网页来显示。

最后总结一下两种方法的适用场景,前一种载入链接的方法适合一个界面(Activity或Fragment)只有一个WebView或者说WebView占很大一块的时候,同时我们要显示的内容是未知的,那么自然是使用loadurl方法更合适,例如QQ聊天的时候对方发送一条链接,当QQ解析出这个文本是一个网址时就通过webview去加载它。而后一种则适合于定制化内容,一般是那种你可以明确的制度网页内容以及要显示的内容时使用,至于好处就是上面说的,定制性要好很多。

深入理解WebView相关推荐

  1. app开发快速理解——webview网页显示

    WebView可以使得网页轻松的内嵌到app里,还可以直接跟js相互调用. webview有两个方法:setWebChromeClient 和 setWebClient setWebClient:主要 ...

  2. 如何设计一个优雅健壮的Android WebView?(上)

    原文链接 https://kaolamobile.github.io/2017/12/10/design-an-elegant-and-powerful-android-webview-part-on ...

  3. 基于腾讯 x5 开源库,提高 webView 开发效率,大概要节约你百分之六十的时间成本。该案例支持处理 js 的交互逻辑且无耦合、同时暴露进度条加载进度、可以监听异常 error 状态、支持视频播放

    YCWebView 项目地址:yangchong211/YCWebView 简介: 基于腾讯 x5 开源库,提高 webView 开发效率,大概要节约你百分之六十的时间成本.该案例支持处理 js 的交 ...

  4. WebView开源库终极方案

    目录介绍 01.前沿说明 1.1 案例展示效果 1.2 该库功能和优势 1.3 相关类介绍说明 1.4 WebView知识点 02.如何使用 2.1 如何引入 2.2 最简单使用 2.3 常用api ...

  5. 如何设计一个优雅健壮的Android WebView?(上) 基于考拉电商平台的WebView实践

    前言 Android应用层的开发有几大模块,其中WebView是最重要的模块之一.网上能够搜索到的WebView资料可谓寥寥,Github上的开源项目也不是很多,更别提有一个现成封装好的WebView ...

  6. 前端需要懂的 APP 容器原理

    本文来自阿里巴巴飞猪前端专家@孝瓘,在移动端容器建设有深厚的经验,热爱前端/iOS/Android 开发,从端视角负责过飞猪H5/RN/Weex/小程序/Flutter容器的建设,本文试图从前端视角, ...

  7. 一些前端相关的面试题(含答案)

    1.         列举几种后端通讯的方法,分别使用的场景. 跨域请求存在的原因:由于浏览器的同源策略,即属于不同域的页面之间不能相互访问各自的页面内容. 跨域的场景: 1.域名不同 www.yan ...

  8. 2020新鲜Java,Android面经

    总结的2020年Java面试经验,含后端开发和客户端开发岗位.加粗部分为常问知识点. 面经总结 Java部分 基础 集合 多线程 JVM 计算机网络 操作系统 算法 Android部分 Java部分 ...

  9. H5 app之初体验

    一.手机APP开发 - 前端打包 1.1 三种APP开发模式 web app 基于html + css + js技术栈开发的APP 通过编辑器的打包功能,将.html文件打包成APP应用 native ...

最新文章

  1. 单片机数码管从00到99C语言_MSP430单片机轻松入门与实践 — 畅学单片机
  2. php自定义函数参数,php自定义函数的参数
  3. SpringCloud+Redis
  4. php mb开启,windows环境下如何为php开启mb_string函数库功能
  5. python基础编程语法-Python基础语法一
  6. web中有关文档元素距离的几个jquery 宽度 width高度height 尺寸 属性
  7. vi+ctags 阅读源码
  8. 网络工程师 第1章 计算机网络概述
  9. python autohotkey_Python pyautogui.hotkey方法代码示例
  10. jdk1.7.0_80下载与安装
  11. 教你几招如何看透一个人一件事!
  12. 戴尔服务器改win7系统,戴尔电脑怎么把Win10系统改装win7系统?
  13. ios中三种随机数方法
  14. 小程序源码:登录已修复零象垃圾废品回收微信小程序源码下载,V2.8.2完整全开源前端+后端
  15. [Go实战]CGO 入门系列-手把手教程3 调用 mysql (c语言类库)为案例
  16. jQuery 插件—— 懒加载
  17. NetDevOps — YANG 协议 — Junos YANG Modules
  18. 短信接口在日常服务类行业的应用
  19. 二、C语言的数据类型—整型数据
  20. Java开发校招面经

热门文章

  1. [电器]“与狼共舞”——张瑞敏(海尔集团董事局主席兼首席执行官)
  2. 这是一份数据量达41.7万开源表格数据集
  3. 设计模式:工厂方法与抽象工厂模式
  4. 【原创】连连看Flex版设计与实现
  5. 2019Android面经 ---已拿网易云音乐内推offer
  6. 魔术之间:自变量与因变量的交互
  7. 无刷三相直流电机电动工具驱动方案设计
  8. 校招面试中常见的算法题整理【长文】
  9. YTU 2404: C语言习题 求sinh(x)
  10. WannaCry勒索病毒分析过程**上**