什么是WebView?
WebView是Android中的原生UI控件,主要用于在app应用中方便地访问远程网页或本地html资源。同时,WebView也在Android中充当Java代码和JS代码之间交互的桥梁。实际上,也可以将WebView看做一个功能最小化的浏览器。
WebView的应用场景
目前很多公司的 App 使用一个 WebView 作为网页加载, App 中的所有网页内容使用 HTML5 进行展示,这样只需要写一次 HTML5 代码,就可以在 Android 和 iOS 平台上运行,这就是所谓的跨平台 。随着 HTML5 的普及,很多 App 都会内嵌 WebView 来加载 HTML5 页面,即 原生和HTML5 共存,这就是当下最流行的「 混合开发 」。HTML5 最大的优势是迭代方便, 只需要修改服务端的 HTML5 页面,App 会同步更新,无论是做活动推广 App 还是及时修复 Bug 都带来的极大的便利。不过 HTML5 劣势也很明显,当网速不尽如人意时候,加载速度会很慢(不知道5G出现后结果会带来什么变革),也就是HTML5 加载受限于网络,没有原生控件流畅,用户体验相对较差, 所以目前完全使用 HTML5 开发 App 并没有成为主流。
基本使用
先加入权限
<uses-permission android:name="android.permission.INTERNET" />
创建WebView
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
获取WebView实例
//获得控件
WebView webView = (WebView) findViewById(R.id.wv_webview);
//加载网页
webView.loadUrl("http://www.baidu.com");
WebView的状态
mWebView.onResume();// 生命周期onResume
mWebView.resumeTimers();//生命周期resumeTimers
mWebView.onPause();//生命周期onPause
mWebView.pauseTimers();//生命周期pauseTimers (上数四个方法都是成对出现)
mWebView.stopLoading();// 停止当前加载
mWebView.clearMatches();// 清除网页查找的高亮匹配字符。
mWebView.clearHistory();// 清除当前 WebView 访问的历史记录
mWebView.clearSslPreferences();//清除ssl信息
mWebView.clearCache(true);//清空网页访问留下的缓存数据。需要注意的时,由于缓存是全局的,所以只要是WebView用到的缓存都会被清空,即便其他地方也会使用到。该方法接受一个参数,从命名即可看出作用。若设为false,则只清空内存里的资源缓存,而不清空磁盘里的。
mWebView.loadUrl("about:blank");// 清空当前加载
mWebView.removeAllViews();// 清空子 View
mWebView.destroy();// 生命周期销毁
前进、后退网页
Webview.canGoBack();//是否可以后退
Webview.goBack();//后退网页
Webview.canGoForward();//是否可以前进
Webview.goForward();//前进网页
Webview.goBackOrForward(intsteps);//以当前的index为起始点前进或者后退到历史记录中指定的steps,如果steps为负数则为后退,正数则为前进
Back键控制网页后退
如果不做任何的处理,触发到Back的时候会直接退出
拦截Back做到后退效果
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
WebView三个重要的部分
1.WebSettings
作用:对WebView进行配置和管理;
2.WebViewClient
作用:处理各种通知 & 请求事件
3.WebChromeClient
作用:辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等等。
WebSettings类
//声明WebSettings子类
WebSettings webSettings = webView.getSettings();
//如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
webSettings.setJavaScriptEnabled(true);
//开启DOM缓存,默认状态下是不支持LocalStorage的
webSettings.setDomStorageEnabled(true);
//支持插件
webSettings.setPluginsEnabled(true);
//设置自适应屏幕,两者合用
webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小
webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小
//缩放操作
webSettings.setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。
webSettings.setBuiltInZoomControls(true); //设置内置的缩放控件。若为false,则该WebView不可缩放
webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件
//缓存
//缓存模式如下:
//LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据
//LOAD_DEFAULT: (默认)根据cache-control决定是否从网络上取数据。
//LOAD_NO_CACHE: 不使用缓存,只从网络获取数据.
//LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据
//不使用缓存
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
//其他细节操作
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存
webSettings.setAllowFileAccess(true); //设置可以访问文件
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式
WebViewClient类
1.shouldOverrideUrlLoading()
//处理WebView到底是本身进行处理,还是跳转手机自带的浏览器
/**
* 1、 默认返回:return super.shouldOverrideUrlLoading(view, url); 这个返回的方法会调用父类方法,也就是跳转至手机浏览器,平时写webview一般都在方法里面写 webView.loadUrl(url); 然后把这个返回值改成下面的false。
* 2、返回: return true; webview处理url是根据程序来执行的。
* 3、返回: return false; webview处理url是在webview内部执行。
*/
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
在这个地方还有一个坑给大家说明一下:
1.由于兼容性问题,在Android7.0以上系统访问shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
2.Android7.0以下系统访问shouldOverrideUrlLoading(WebView view, String url)
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()
//在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次,除非本地有当前 url 对应有缓存,否则就会加载。
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); //可做其他处理
}
});
7.shouldInterceptRequest()这是一个很重要的方法
//WebView拦截请求,重定向
/**
* 代码中重写了两个shouldInterceptRequest方法
* 1.shouldInterceptRequest (WebView view, String url);
* 2.shouldInterceptRequest(WebView view, android.webkit.WebResourceRequest request):
* 其中shouldInterceptRequest (WebView view, String url)在API 21过时。
*/
webView.setWebViewClient(new WebViewClient() {
@Override
public void shouldInterceptRequest(WebView view, android.webkit.WebResourceRequest request) {
//WebView中有JS、PNG图片等资源可以截取并更换资源文件
}
});
WebChromeClient类
1.onProgressChanged()
//获得网页的加载进度
webview.setWebChromeClient(new WebChromeClient(){
@Override
public void onProgressChanged(WebView view, int newProgress) {
// 可以与progressBarView类似的View绑定加载进度
});
2.onReceivedTitle()
//接收web页面的 Title。
/**
* 每个网页的页面都有一个标题,比如www.baidu.com这个页面的标题即“百度一下,你就 知道”,那么如何知道当前webview正在加载的页面的title并进行设置呢?
*/
webview.setWebChromeClient(new WebChromeClient(){
@Override
public void onReceivedTitle(WebView view, String title) {
titleview.setText(title);
}
WebView和JavaScript的交互
1、使用系统方法 addJavascriptInterface 注入 java 对象来实现。
2、利用 WebViewClient 中 shouldOverrideUrlLoading (WebView view, String url) 接口,拦截操作。这个就是很多公司在用的 scheme 方式,通过制定url协议,双方各自解析,使用iframe来调用native代码,实现互通。
3、利用 WebChromeClient 中的 onJsAlert、onJsConfirm、onJsPrompt 提示接口,同样也是拦截操作。
示例代码:
//开启Js可用
mWebView.getSettings().setJavaScriptEnabled(true);
// 创建要注入的 Java 类
public class NativeInterface {
private Context mContext;
public NativeInterface(Context context) {
mContext = context;
}
@JavascriptInterface
public void hello() {
Toast.makeText(mContext, "hello", Toast.LENGTH_SHORT).show();
}
@JavascriptInterface
public void hello(String params) {
Toast.makeText(mContext, params, Toast.LENGTH_SHORT).show();
}
@JavascriptInterface
public String getAndroid() {
Toast.makeText(mContext, "getAndroid", Toast.LENGTH_SHORT).show();
return "Android data";
}
}
// WebView 注入即可
mWebView.addJavascriptInterface(new NativeInterface(this), "AndroidNative");
//Js编写
<script>
function callHello(){
AndroidNative.hello();
}
function callHello1(){
AndroidNative.hello('hello Android');
}
function callAndroid(){
var temp = AndroidNative.getAndroid();
console.log(temp);
alert(temp);
}
</script>
WebView内存泄漏问题
//mWebView=new WebView(this);
mWebView=new WebView(getApplicationContext());
LinearLayout linearLayout = findViewById(R.id.xxx);
linearLayout.addView(mWebView);
// onDestroy()方法中调用:
@Override
protected void onDestroy() {
if( mWebView!=null) {
mWebView.setVisibility(View.GONE);
mWebView.removeAllViews();
mWebView.destroy();
}
super.onDestroy();
}
感谢大家能够看完本篇文章,如果有说的不正确的地方或者有疑问,可以互相交流。