WebView的使用详解-程序员宅基地

技术标签: 华为  harmonyos  

WebView

现在Android开发基本都会用到WebView,所以自己准备系统的整理下,供自己学习之用.

1.简介

WebView是一个基于webkit引擎、展现web页面的控件。

Android的Webview在低版本和高版本采用了不同的webkit版本内核,4.4后直接使用了Chrome。

2.作用

显示和渲染Web页面

直接使用html文件(网络上或本地assets中)作布局

可和JavaScript交互调用

WebView控件功能强大,除了具有一般View的属性和设置外,还可以对url请求、页面加载、渲染、页面交互进行强大的处理。

3.使用介绍

一般来说Webview可单独使用,可联合其子类一起使用,下面会介绍几种:

1.Webview自身的常见方法;

2.Webview的最常用的子类

3.(WebSettings类、WebViewClient类、WebChromeClient类)

Android和Js的交互

3.1 Webview常用方法

3.1.1 加载URL

可以根据资源分为三种:

方式1. 加载一个网页:webView.loadUrl(“页面不存在_百度搜索);

方式2:加载apk包中的html页面

webView.loadUrl(“file:///android_asset/test.html”);

方式3:加载手机本地的html页面

webView.loadUrl(“content://com.android.htmlfileprovider/sdcard/test.html”);

方式4: 加载 HTML 页面的一小段内容

WebView.loadData(String data, String mimeType, String encoding)

参数说明:参数1:需要截取展示的内容

内容里不能出现 ’#’, ‘%’, ‘\’ , ‘?’ 这四个字符,若出现了需用 %23, %25, %27, %3f 对应来替代,否则会出现异常

参数2:展示内容的类型

参数3:字节码

3.1.2 WebView的状态

激活WebView为活跃状态,能正常执行网页的响应webView.onResume() ;

当页面被失去焦点被切换到后台不可见状态,需要执行onPause.通过onPause动作通知内核暂停所有的动作,比如DOM的解析、plugin的执行、JavaScript执行。webView.onPause();

当应用程序(存在webview)被切换到后台时,这个方法不仅仅针对当前的webview而是全局的全应用程序的webview.它会暂停所有webview的layout,parsing,javascripttimer。降低CPU功耗。

webView.pauseTimers()恢复pauseTimers状态

webView.resumeTimers();

销毁Webview. 在关闭了Activity时,如果Webview的音乐或视频,还在播放。就必须销毁Webview

但是注意:webview调用destory时,webview仍绑定在Activity上. 这是由于自定义webview构建时传入了该Activity的context对象. 因此需要先从父容器中移除webview,然后再销毁webview:

rootLayout.removeView(webView);

webView.destroy();

3.1.2 关于前进 / 后退网页

是否可以后退

Webview.canGoBack()

后退网页

Webview.goBack()

是否可以前进

Webview.canGoForward()

前进网页

Webview.goForward()

以当前的index为起始点前进或者后退到历史记录中指定的steps. 如果steps为负数则为后退,正数则为前进

Webview.goBackOrForward(intsteps)

常见用法:Back键控制网页后退

问题:在不做任何处理前提下 ,浏览网页时点击系统的“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); }

3.1.3 清除缓存数据

清除网页访问留下的缓存. 由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.

Webview.clearCache(true);

清除当前webview访问的历史记录. 只会webview访问历史记录里的所有记录除了当前访问记录

Webview.clearHistory();

这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据

Webview.clearFormData();

3.2 常用类

3.2.1 WebSettings类

作用:对WebView进行配置和管理

配置步骤 & 常见方法:

配置步骤1:添加访问网络权限(AndroidManifest.xml)

- 1.这是前提!这是前提!这是前提!
- 2.<uses-permission android:name="android.permission.INTERNET"/>

配置步骤2:生成一个WebView组件(有两种方式)

方式1:直接在在Activity中生成

WebView webView = new WebView(this)

方法2:在Activity的layout文件里添加webview控件:

WebView webview = (WebView) findViewById(R.id.webView1);

配置步骤3:进行配置-利用WebSettings子类(常见方法)

声明WebSettings子类

WebSettings webSettings = webView.getSettings();

如果访问的页面中要与Javascript交互,

则webview必须设置支持Javascript

webSettings.setJavaScriptEnabled(true);

若加载的 html 里有JS 在执行动画等操作,会造成资源浪费(CPU、电量)

在 onStop 和 onResume 里分别把 setJavaScriptEnabled() 给设置成 false 和 true 即可

支持插件

webSettings.setPluginsEnabled(true);设置自适应屏幕,两者合用

webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小

webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小

缩放操作

webSettings.setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。

webSettings.setBuiltInZoomControls(true); //设置内置的缩放控件。若为false,则该WebView不可缩放

webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件

其他细节操作

webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存

webSettings.setAllowFileAccess(true); //设置可以访问文件

webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口

webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片

webSettings.setDefaultTextEncodingName(“utf-8”);//设置编码格式

常见用法:设置WebView缓存

* 当加载 html 页面时,WebView会在/data/data/包名目录下生成 database 与 cache 两个文件夹
* 请求的 URL记录保存在 WebViewCache.db,而 URL的内容是保存在 WebViewCache 文件夹下
* 是否启用缓存:

优先使用缓存:

WebView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);

缓存模式如下:

LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据

LOAD_DEFAULT: (默认)根据cache-control决定是否从网络上取数据。

LOAD_NO_CACHE: 不使用缓存,只从网络获取数据.

LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。

不使用缓存:

WebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);

结合使用(离线加载)

if (NetStatusUtil.isConnected(getApplicationContext())) {

webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);//根据cache-control决定是否从网络上取数据。

} else {

webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);//没网,则从本地获取,即离线加载

}

webSettings.setDomStorageEnabled(true); // 开启 DOM storage API 功能

webSettings.setDatabaseEnabled(true); //开启 database storage API 功能

webSettings.setAppCacheEnabled(true);//开启 Application Caches 功能

String cacheDirPath = getFilesDir().getAbsolutePath() + APP_CACAHE_DIRNAME;

webSettings.setAppCachePath(cacheDirPath); //设置 Application Caches 缓存目录

注意: 每个 Application 只调用一次 WebSettings.setAppCachePath(),WebSettings.setAppCacheMaxSize()

3.2.2 WebViewClient类

作用:处理各种通知 & 请求事件

常见方法:

常见方法1:shouldOverrideUrlLoading()

作用:打开网页时不调用系统浏览器, 而是在本WebView中显示;在网页上的所有加载都经过这个方法,这个函数我们可以做很多操作。

步骤1. 定义Webview组件

Webview webview = (WebView) findViewById(R.id.webView1);

步骤2. 选择加载方式

方式1. 加载一个网页:

webView.loadUrl(“http://www.google.com/”);

方式2:加载apk包中的html页面

webView.loadUrl(“file:///android_asset/test.html”);

方式3:加载手机本地的html页面

webView.loadUrl(“content://com.android.htmlfileprovider/sdcard/test.html”);

步骤3. 复写shouldOverrideUrlLoading()方法,使得打开网页时不调用系统浏览器, 而是在本WebView中显示

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

常见方法2:onPageStarted()

作用:开始载入页面调用的,我们可以设定一个loading的页面,告诉用户程序在等待网络响应。

webView.setWebViewClient(new WebViewClient(){ @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { //设定加载开始的操作 } });

常见方法3:onPageFinished()

作用:在页面加载结束时调用。我们可以关闭loading 条,切换程序动作。

webView.setWebViewClient(new WebViewClient(){ @Override public void onPageFinished(WebView view, String url) { //设定加载结束的操作 } });

常见方法4:onLoadResource()

作用:在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。

webView.setWebViewClient(new WebViewClient(){ @Override public boolean onLoadResource(WebView view, String url) { //设定加载资源的操作 } });

常见方法5:onReceivedError()

作用:加载页面的服务器出现错误时(如404)调用。

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

步骤1:写一个html文件(error_handle.html),用于出错时展示给用户看的提示页面

步骤2:将该html文件放置到代码根目录的assets文件夹下

步骤3:复写WebViewClient的onRecievedError方法

该方法传回了错误码,根据错误类型可以进行不同的错误分类处理

webView.setWebViewClient(new WebViewClient(){ @Override public 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; } } });

常见方法6:onReceivedSslError()

作用:处理https请求

webView默认是不处理https请求的,页面显示空白,需要进行如下设置:

webView.setWebViewClient(new WebViewClient() { @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { handler.proceed(); //表示等待证书响应 // handler.cancel(); //表示挂起连接,为默认方式 // handler.handleMessage(null); //可做其他处理 } });

3.2.3 WebChromeClient类

作用:辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等等。

常见使用:

常见方法1: onProgressChanged()

作用:获得网页的加载进度并显示

`webview.setWebChromeClient(new WebChromeClient(){

  @Override
  public void onProgressChanged(WebView view, int newProgress) {
  	if (newProgress < 100) {
  		String progress = newProgress + "%";
  		progress.setText(progress);
  	} else {
  }

});`

常见方法2: onReceivedTitle()

作用:获取Web页中的标题

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

`webview.setWebChromeClient(new WebChromeClient(){

  @Override
  	public void onReceivedTitle(WebView view, String title) {
  		titleview.setText(title);
  }`

常见方法3: onJsAlert(

作用:支持javascript的警告框

一般情况下在 Android 中为 Toast,在文本里面加入\n就可以换行

webview.setWebChromeClient(new WebChromeClient() { @Override public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { new AlertDialog.Builder(MainActivity.this) .setTitle("JsAlert") .setMessage(message) .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.confirm(); } }) .setCancelable(false) .show(); return true; }

常见方法4: onJsConfirm()

作用:支持javascript的确认框

`webview.setWebChromeClient(new WebChromeClient() {

  @Override
  public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
  	new AlertDialog.Builder(MainActivity.this)
  	.setTitle("JsConfirm")
  	.setMessage(message)
  	.setPositiveButton("OK", new DialogInterface.OnClickListener() {
  		@Override
  		public void onClick(DialogInterface dialog, int which) {
  			result.confirm();
  		}
  	})
  	.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
  		@Override
  		public void onClick(DialogInterface dialog, int which) {
  			result.cancel();
  		}
  	})
  	.setCancelable(false)
  	.show();
  // 返回布尔值:判断点击时确认还是取消
  // true表示点击了确认;false表示点击了取消;
  return true;
  }`

常见方法5: onJsPrompt()

作用:支持javascript输入框

点击确认返回输入框中的值,点击取消返回 null。

`webview.setWebChromeClient(new WebChromeClient() {

@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, final JsPromptResult result) {
final EditText et = new EditText(MainActivity.this);
et.setText(defaultValue);
new AlertDialog.Builder(MainActivity.this)
.setTitle(message)
.setView(et)
.setPositiveButton(“OK”, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm(et.getText().toString());
}
})
.setNegativeButton(“Cancel”, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
})
.setCancelable(false)
.show();

  return true;
1
}`

3.3 WebView与JavaScript的交互

3.3.1 JS注入漏洞

addJavascriptInterface 接口引起远程代码执行漏洞

webView.addJavascriptInterface(new JSObject(), “myObj”);

参数1:Android的本地对象

参数2:JS的对象

通过对象映射将Android中的本地对象和JS中的对象进行关联,从而实现JS调用Android的对象和方法

产生原因: JS拿到Android这个对象后,可以调用这个Android对象中的所有方法,包括(java.lang.Runtime类),从而进行任意代码执行.

eg: 执行对应命令获取本地设备SD卡中的文件信息造成信息泄漏

解决方案:

第一种: 4.2 版本之后, 在被调用的函数上加上@JavascriptInterface 注解,避免漏洞攻击

第二种: 4.2版本之前. 采用拦截prompt()进行漏洞修复.

步骤:

(1) 先继承自WebView,重写addJavascriptInterface方法,在内部维护一个对象映射关系的Map, 将要添加的JS接口放入该Map

(2) 在Webview加载前时,加载一段本地JS代码

a.让JS调用 提供的javascript方法, 通过调用prompt()把JS中的信息传给Android端

b.在Android端的onJsPrompt()中,解析传递过来的信息,再通过反射机制调用Java对象中的方法.有个中间层来保证安全调用.

3.3.2 JSBridge

定义: 就是给JavaScript 提供调用Native功能的接口

核心: 构建Native 和非Native间消息通信的通道,双向通信的通道.

双向通信:

JS向Native发送消息,调用相关功能,通知Native当前JS的相关状态

Native向JS发送消息,回溯调用结果,消息推送,通知JS当前Native的状态

3.4 注意事项:如何避免WebView内存泄露?

3.4.1 不在xml中定义 Webview ,而是在需要的时候在Activity中创建,并且Context使用 getApplicationgContext()

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); mWebView = new WebView(getApplicationContext()); mWebView.setLayoutParams(params); mLayout.addView(mWebView);

3.4.2 在 Activity 销毁( WebView )的时候,先让 WebView 加载null内容,然后移除 WebView,再销毁 WebView,最后置空。

@Override protected void onDestroy() { if (mWebView != null) { mWebView.loadDataWithBaseURL(null, "
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/LJQDMY/article/details/132977732

智能推荐

JWT(Json Web Token)实现无状态登录_无状态token登录-程序员宅基地

文章浏览阅读685次。1.1.什么是有状态?有状态服务,即服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如tomcat中的session。例如登录:用户登录后,我们把登录者的信息保存在服务端session中,并且给用户一个cookie值,记录对应的session。然后下次请求,用户携带cookie值来,我们就能识别到对应session,从而找到用户的信息。缺点是什么?服务端保存大量数据,增加服务端压力 服务端保存用户状态,无法进行水平扩展 客户端请求依赖服务.._无状态token登录

SDUT OJ逆置正整数-程序员宅基地

文章浏览阅读293次。SDUT OnlineJudge#include<iostream>using namespace std;int main(){int a,b,c,d;cin>>a;b=a%10;c=a/10%10;d=a/100%10;int key[3];key[0]=b;key[1]=c;key[2]=d;for(int i = 0;i<3;i++){ if(key[i]!=0) { cout<<key[i.

年终奖盲区_年终奖盲区表-程序员宅基地

文章浏览阅读2.2k次。年终奖采用的平均每月的收入来评定缴税级数的,速算扣除数也按照月份计算出来,但是最终减去的也是一个月的速算扣除数。为什么这么做呢,这样的收的税更多啊,年终也是一个月的收入,凭什么减去12*速算扣除数了?这个霸道(不要脸)的说法,我们只能合理避免的这些跨级的区域了,那具体是那些区域呢?可以参考下面的表格:年终奖一列标红的一对便是盲区的上下线,发放年终奖的数额一定一定要避免这个区域,不然公司多花了钱..._年终奖盲区表

matlab 提取struct结构体中某个字段所有变量的值_matlab读取struct类型数据中的值-程序员宅基地

文章浏览阅读7.5k次,点赞5次,收藏19次。matlab结构体struct字段变量值提取_matlab读取struct类型数据中的值

Android fragment的用法_android reader fragment-程序员宅基地

文章浏览阅读4.8k次。1,什么情况下使用fragment通常用来作为一个activity的用户界面的一部分例如, 一个新闻应用可以在屏幕左侧使用一个fragment来展示一个文章的列表,然后在屏幕右侧使用另一个fragment来展示一篇文章 – 2个fragment并排显示在相同的一个activity中,并且每一个fragment拥有它自己的一套生命周期回调方法,并且处理它们自己的用户输_android reader fragment

FFT of waveIn audio signals-程序员宅基地

文章浏览阅读2.8k次。FFT of waveIn audio signalsBy Aqiruse An article on using the Fast Fourier Transform on audio signals. IntroductionThe Fast Fourier Transform (FFT) allows users to view the spectrum content of _fft of wavein audio signals

随便推点

Awesome Mac:收集的非常全面好用的Mac应用程序、软件以及工具_awesomemac-程序员宅基地

文章浏览阅读5.9k次。https://jaywcjlove.github.io/awesome-mac/ 这个仓库主要是收集非常好用的Mac应用程序、软件以及工具,主要面向开发者和设计师。有这个想法是因为我最近发了一篇较为火爆的涨粉儿微信公众号文章《工具武装的前端开发工程师》,于是建了这么一个仓库,持续更新作为补充,搜集更多好用的软件工具。请Star、Pull Request或者使劲搓它 issu_awesomemac

java前端技术---jquery基础详解_简介java中jquery技术-程序员宅基地

文章浏览阅读616次。一.jquery简介 jQuery是一个快速的,简洁的javaScript库,使用户能更方便地处理HTML documents、events、实现动画效果,并且方便地为网站提供AJAX交互 jQuery 的功能概括1、html 的元素选取2、html的元素操作3、html dom遍历和修改4、js特效和动画效果5、css操作6、html事件操作7、ajax_简介java中jquery技术

Ant Design Table换滚动条的样式_ant design ::-webkit-scrollbar-corner-程序员宅基地

文章浏览阅读1.6w次,点赞5次,收藏19次。我修改的是表格的固定列滚动而产生的滚动条引用Table的组件的css文件中加入下面的样式:.ant-table-body{ &amp;amp;::-webkit-scrollbar { height: 5px; } &amp;amp;::-webkit-scrollbar-thumb { border-radius: 5px; -webkit-box..._ant design ::-webkit-scrollbar-corner

javaWeb毕设分享 健身俱乐部会员管理系统【源码+论文】-程序员宅基地

文章浏览阅读269次。基于JSP的健身俱乐部会员管理系统项目分享:见文末!

论文开题报告怎么写?_开题报告研究难点-程序员宅基地

文章浏览阅读1.8k次,点赞2次,收藏15次。同学们,是不是又到了一年一度写开题报告的时候呀?是不是还在为不知道论文的开题报告怎么写而苦恼?Take it easy!我带着倾尽我所有开题报告写作经验总结出来的最强保姆级开题报告解说来啦,一定让你脱胎换骨,顺利拿下开题报告这个高塔,你确定还不赶快点赞收藏学起来吗?_开题报告研究难点

原生JS 与 VUE获取父级、子级、兄弟节点的方法 及一些DOM对象的获取_获取子节点的路径 vue-程序员宅基地

文章浏览阅读6k次,点赞4次,收藏17次。原生先获取对象var a = document.getElementById("dom");vue先添加ref <div class="" ref="divBox">获取对象let a = this.$refs.divBox获取父、子、兄弟节点方法var b = a.childNodes; 获取a的全部子节点 var c = a.parentNode; 获取a的父节点var d = a.nextSbiling; 获取a的下一个兄弟节点 var e = a.previ_获取子节点的路径 vue