Android WebView基本用法

webview网页图

序言


WebView

extends AbsoluteLayout
implements ViewGroup.OnHierarchyChangeListener ViewTreeObserver.OnGlobalFocusChangeListener


java.lang.Object
android.view.View
android.view.ViewGroup
android.widget.AbsoluteLayout
android.webkit.WebView


Class Overview

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 includes methods to navigate forward and backward through a history, zoom in and out, perform text searches and more.

概述
WebView是一个显示网页的视图。这个类你可以滚动自己的Web浏览器或者只显示你的活动中的一些在线内容的基础。它使用WebKit渲染引擎来显示网页,包括向前和向后浏览历史记录,放大和缩小,进行文本搜索等方法。

正文


基本用法

默认情况下,WebView不支持JavaScript,web页面的错误也会被忽略,如果只是用Webview来显示网页而不用交互,默认配置就可以了。如果需要交互,就需要自定义配置了。

1. WebView配置

1)添加访问网络权限(AndroidManifest.xml)

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

2)WebView配置

//不现实水平滚动条
mWebView.setHorizontalScrollBarEnabled(false);
//不现实垂直滚动条
mWebView.setVerticalScrollBarEnabled(false);
//滚动条在WebView内侧显示
mWebView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);
//滚动条在WebView外侧显示
mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
//获取触摸焦点
mWebView.requestFocusFromTouch();

3)WebSettings子类配置

//声明WebSettings子类
WebSettings webSettings = webView.getSettings();

//插件支持设置
webSettings.setJavaScriptEnabled(true); // 是否支持Javascript,默认false
webSettings.setPluginsEnabled(true); //是否支持插件
webSettings.setSupportMultipleWindows(false);// 是否支持多窗口,默认false
webSettings.setJavaScriptCanOpenWindowsAutomatically(false);// 是否可用Javascript(window.open)打开窗口,默认false

//设置自适应屏幕,两者合用
webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小 
webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小

//缩放操作设置
webSettings.setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提
webSettings.setBuiltInZoomControls(true); //设置内置的缩放控件。若为false,则该WebView不可缩放
webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件

//资源加载设置
webSettings.setLoadsImagesAutomatically(true); // 是否自动加载图片
webSettings.setBlockNetworkImage(false); // 禁止加载网络图片
webSettings.setBlockNetworkLoads(false); // 禁止加载所有网络资源

//资源访问设置
webSettings.setAllowContentAccess(true); //是否可访问Content Provider的资源,默认 true
webSettings.setAllowFileAccess(true);  //是否可访问本地文件,默认 true
webSettings.setAllowFileAccessFromFileURLs(false); //是否允许通过file url加载的Javascript读取本地文件,默认 false
webSettings.setAllowUniversalAccessFromFileURLs(false);//是否允许通过file url加载的Javascript读取全部资源(包括文件,http,https),默认 false

//存储缓存设置
webSettings.setDomStorageEnabled(true); //是否启用 DOM storage API,默认 false
webSettings.setDatabaseEnabled(true);  //是否启用 Database storage API,默认 false
webSettings.setAppCacheEnabled(true); //是否启用缓存
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //缓存模式设置

//默认文本设置
webSettings.setDefaultFontSize(16);// 默认文字尺寸,默认值16,取值范围1-72
webSettings.setDefaultFixedFontSize(16);// 默认等宽字体尺寸,默认值16
webSettings.setMinimumFontSize(8);// 最小文字尺寸,默认值 8
webSettings.setMinimumLogicalFontSize(8); // 最小文字逻辑尺寸,默认值 8
webSettings.setTextZoom(100); // 文字缩放百分比,默认值 100

2. WebView缓存
  • 当加载 html页面时,WebView会在/data/data/包名目录下生成databasecache两个文件夹
  • 请求的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 (NetUtil.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 缓存目录
3. 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();
4. 加载方式

1)加载远程网页

webView.loadUrl("http://www.baidu.com");

2)加载assets目录下的本地网页

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

3)加载手机本地网页

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

4)加载HTML代码片段

webView.loadData(data, "text/html", "utf-8");
//或者
webView.loadDataWithBaseURL(null, data, "text/html", "utf-8", null);

loadDataWithBaseURL()loadData()多两个参数,可以指定HTML代码片段中相关资源的相对根路径,也可以指定历史Url。两个方法的其余三个参数相同。其次,两个方法加载的HTML代码片段有些不同,loadData()中的HTML data中不能包含'#', '%', '\', '?'四种特殊字符

5. WebViewClient类
/**在开始加载网页时会回调*/
public void onPageStarted(WebView view, String url, Bitmap favicon)
/**在结束加载网页时会回调*/
public void onPageFinished(WebView view, String url)
/**拦截 url 跳转,在里边添加点击链接跳转或者操作*/
public boolean shouldOverrideUrlLoading(WebView view, String url)
/**加载错误的时候会回调,在其中可做错误处理,比如再请求加载一次,或者提示404的错误页面 */
public void onReceivedError(WebView view, int errorCode,String description, String failingUrl)
/**当接收到https错误时,会回调此函数,在其中可以做错误处理*/
public void onReceivedSslError(WebView view, SslErrorHandler handler,SslError error)
/** 在每一次请求资源时,都会通过这个函数来回调*/
public WebResourceResponse shouldInterceptRequest(WebView view,String url)
6. WebChromeClient类
/**处理 alert 弹出框 */
public boolean onJsAlert(WebView view, String url, String message, JsResult result)
/**处理 prompt 弹出框 */
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result)
/**处理 confirm 弹出框 */
public boolean onJsConfirm(WebView view, String url, String message, JsResult result)
/**获取网站的图标 */
public void onReceivedIcon(WebView view, Bitmap icon)
/**获取当前网页的标题 */
public void onReceivedTitle(WebView view, String title)
/**打印 Console 信息 */
public boolean onConsoleMessage(ConsoleMessage consoleMessage)
7. 管理Cookies

1)Cookie设置

CookieSyncManager.createInstance(this);
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
String cookie = "name=xxx;age=18";
cookieManager.setCookie(URL, cookie);
CookieSyncManager.getInstance().sync();

2)获取Cookie

CookieManager cookieManager = CookieManager.getInstance();
String cookie = cookieManager.getCookie(URL);

3)清除Cookie

CookieSyncManager.createInstance(context);
CookieManager cookieManager = CookieManager.getInstance();
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    cookieManager.removeAllCookies(null);
} else {
    cookieManager.removeAllCookie();
}
CookieSyncManager.getInstance().sync();
8. 清除Cache
//清除网页访问留下的缓存
clearCache(true);
//清除当前webview访问的历史记录,会清理除了当前访问记录的所有访问历史记录
clearHistory();
//这个仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据
clearFormData();
//清理Webview缓存数据库  
deleteDatabase("webview.db"); 
deleteDatabase("webviewCache.db"); 
9. 前进、后退和刷新
reload();//刷新
goBack();//后退
goForward();//前进
goBackOrForward(int steps);//以当前index为起始点前进或后退到历史记录中指定steps,若steps为负数则后退,正数则前进
canGoForward();//是否可以前进
canGoBack();//是否可以后退

在不做任何处理前提下,点击返回键,整个activity会销毁直接退出。如果想要不退出当前activity,只想返回上一个HTML页面,那么就需要在返回监听事件做处理:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (event.getAction() == KeyEvent.ACTION_DOWN) {
        if (keyCode == KeyEvent.KEYCODE_BACK && webview.canGoBack()) {
            webview.goBack();//后退
            //webview.goForward();//前进
            return true;
        }
    }
    return super.onKeyDown(keyCode, event);
}
10. 判断WebView是否已经滚动到页面顶端或者底端
  • getScrollY()方法返回的是当前可见区域的顶端距整个页面顶端的距离,也就是当前内容滚动的距离
  • getHeight()或者getBottom()方法都返回当前WebView 这个容器的高度
  • getContentHeight()方法返回的是整个html 的高度,但并不等同于当前整个页面的高度。因为WebView 有缩放功能,所以当前整个页面的高度实际上应该是原始 Html 的高度再乘上缩放比例。 因此,准确的判断方法应该是:
if(webview.getContentHeight()* webview.getScale() == (webview.getHeight() + webview.getScrollY())) { 
    //已经处于底端
 }
11. 跳转浏览器加载

如果不想在 webview 中显示网页,而是直接跳转到浏览器的话,可以这样调用:

    Uri uri = Uri.parse("https://www.baidu.com"); 
    Intent intent = new Intent(Intent.ACTION_VIEW, uri); 
    startActivity(intent);
12. 自定义拦截

1)拦截某一个链接不执行此链接,执行指定跳转到其他activity页面

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
  //return super.shouldOverrideUrlLoading(view, request);
    if(!TextUtils.isEmpty(url)) {
        if("login".contains(url)) {
            Intent intent = new Intent(this,LoginActivity.class);
            startActivity(intent);
            return false;
        } else {
            //返回值为true时在WebView中打开,为false时调用浏览器打开
            return true;
        }
    }   
}

从API 21起弃用该方法,用shouldOverrideUrlLoading(WebView view, WebResourceRequest request)来替换

@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
    //return super.shouldOverrideUrlLoading(view, request);
    String url = request.getUrl().toString();
    if(!TextUtils.isEmpty(url)) {
        if("login".contains(url)) {
            Intent intent = new Intent(this,LoginActivity.class);
            startActivity(intent);
            return false;
        } else {
            //返回值为true时在WebView中打开,为false时调用浏览器打开
            return true;
        }
    }   
}

2)拦截某一个要跳转的url链接,并对请求的url链接做修改

webView.setWebViewClient(new WebViewClient() {
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view,  String url) {
        if (url.contains("logo")) {
            String result = "<html>\n" +
                            "<title>百度</title>\n" +
                            "<body>\n" +
                            "<a href=\"www.baidu.com\">百度</a>,百度一下,就知道了\n" +
                            "</body>\n" +
                            "<html>";
            WebResourceResponse response = new WebResourceResponse("text/html",
                    "utf-8",
                    new ByteArrayInputStream(result.getBytes()));
        } else {
            ...
        }
        return response;
    }
});

从API 21起弃用该方法,用shouldInterceptRequest(WebView view, WebResourceRequest request)来替换

webView.setWebViewClient(new WebViewClient() {
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view,  WebResourceRequest request) {
        String url = request.getUrl().toString();   
        if (url.contains("logo")) {
            String result = "<html>\n" +
                            "<title>百度</title>\n" +
                            "<body>\n" +
                            "<a href=\"www.baidu.com\">百度</a>,百度一下,就知道了\n" +
                            "</body>\n" +
                            "<html>";
            WebResourceResponse response = new WebResourceResponse("text/html",
                    "utf-8",
                    new ByteArrayInputStream(result.getBytes()));
        } else {
            ...
        }
        return response;
    }
});
13. 设置标题

在用WebView加载的页面中,如果页面内有多个页面跳转链接,就不能把标题写死,需要动态获取WebView当前页面的标题,可以通过对WebChromeClient.onReceivedTitle()方法的重写来实现。

mWebView.setWebChromeClient(new WebChromeClient() {
    @Override
    public void onReceivedTitle(WebView view, String title) {
        super.onReceivedTitle(view, title);
        //onReceivedTitle可以回调网页的title
        tv_title.setText(title);
    }
});
14. 设置加载进度

WebView在加载网页时,默认是没有加载进度的,我们不能准确了解网页的加载进度。为了提高用户体验,我们可以在WebView中加入进度条显示加载进度。

mWebView.setWebChromeClient(new WebChromeClient() {
    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        //使用控件ProgressDialog来显示更新进度条示数
        if (newProgress == 100) {
            mProgressDlg.dismiss();
        } else {
            mProgressDlg.setProgress(newProgress);
        }
    }
    @Override
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
        super.onReceivedError(view, errorCode, description, failingUrl);
        //在error发生时也进行取消
        mProgressDlg.dismiss();
    }
});
15. 错误处理

某些时候网络不好或者没有网络,这时候设备就访问不到服务器了,加载不了Html页面。一般情况下,当我们的设备无网络情况下加载一个Html时,会自行弹出Android默认的错误页面,这样用户体验会很差。—— 《Android WebView加载网页失败异常处理》

参考

WebView官方文档,开启传送门

结语


至此,关于WebView的基本属性及用法都整理在这儿,有需要的朋友可供参考。

推荐阅读更多精彩内容