之前webView的使用很大多局限于显示网页,现在有机会重头梳理下整理成如下笔记:
基本用法
//方式1. 加载一个网页:
mWebView.loadUrl("https://www.baidu.com");
//方式2:加载apk包中的html页面
mWebView.loadUrl("file://android_asset/test.html");
//方式3:加载手机本地的html页面
mWebView.loadUrl("content://com.example.frc.myapplication/sdcard/test.html");
// 方式4: 加载 HTML 页面的一小段内容
mWebView.loadData(htmlStr, "text/html", null);
// 参数说明:
// 参数1:需要截取展示的内容
// 内容里不能出现 ’#’, ‘%’, ‘\’ , ‘?’ 这四个字符,若出现了需用 %23, %25, %27, %3f 对应来替代,否则会出现异常
// 参数2:展示内容的类型
// 参数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();
结合Activity的状态使用:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//在当前Activity中处理并消费掉该 Back 事件
if ((keyCode == KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onResume() {
super.onResume();
mWebView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mWebView.onPause();
}
@Override
protected void onStop() {
super.onStop();
}
@Override
protected void onDestroy() {
if (mWebView != null) {
//清除网页访问留下的缓存
//由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.
// mWebView.clearCache(true);
//在关闭了Activity时,如果Webview的音乐或视频,还在播放。就必须销毁Webview
mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
mWebView.clearHistory();
//但是注意:webview调用destory时,webview仍绑定在Activity上
//这是由于自定义webview构建时传入了该Activity的context对象
//因此需要先从父容器中移除webview,然后再销毁webview:
mRootView.removeView(mWebView);
mWebView.destroy();
mWebView = null;
}
super.onDestroy();
}
WebSettings
获取WebSettings
//获取WebSettings
WebSettings webSettings = mWebView.getSettings();
setWebSettings(webSettings);
一些常用的设置:
SuppressLint("SetJavaScriptEnabled")
private void setWebSettings(WebSettings webSettings) {
webSettings.setJavaScriptEnabled(true);//支持JavaScript
// Your code should not invoke setJavaScriptEnabled if you are not sure that your app really requires JavaScript support.
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);//支持通过JS打开新窗口
//缓存设置
webSettings.setAppCacheEnabled(false);///开启 Application Caches 功能
String cacheDirPath = getFilesDir().getAbsolutePath() + APP_CACAHE_DIRNAME;
webSettings.setAppCachePath(cacheDirPath);//设置Application Caches 缓存目录 该方法在一个app钟只能调一次
//自适应屏幕
webSettings.setUseWideViewPort(true);//将图片调整到适合webview的大小
webSettings.setLoadWithOverviewMode(true);// 缩放至屏幕的大小
//缩放处理
webSettings.setSupportZoom(true);//支持缩放
webSettings.setBuiltInZoomControls(true);//设置内置的缩放控件
webSettings.setDisplayZoomControls(false);//隐藏原生缩放控件
//others
webSettings.setLoadsImagesAutomatically(true);//支持自动加载图片
webSettings.setDefaultTextEncodingName("utf-8");
webSettings.setDefaultFixedFontSize(18);
webSettings.setDefaultFontSize(20);
webSettings.setAllowFileAccess(true);//设置可以访问文件
}
根据网络情况设置加载模式:
if (NetWorkUtils.isNetworkAvailable(WebViewActivity.this)) {
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
} else {
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
}
缓存模式如下:
//LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据
//LOAD_DEFAULT: (默认)根据cache-control决定是否从网络上取数据。
//LOAD_NO_CACHE: 不使用缓存,只从网络获取数据.
//LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,都使用缓存中的数据如果没有从网络获取
当加载 html 页面时,WebView会在/data/data/包名目录下生成 database 与 cache 两个文件夹
请求的 URL记录保存在 WebViewCache.db,而 URL的内容是保存在 WebViewCache 文件夹下
WebViewClient
/**
* 如果不设置WebViewClient的话,则 WebView 会请求 Activity 管理者选择合适的 URL 处理方式,一般情况就是启动浏览器来加载URL;
*
* @param webView webview
*/
private void setWebViewClient(WebView webView) {
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
view.loadUrl(request.getUrl().toString());
}
return true;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Log.e("web", "load " + url + " start");
super.onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished(WebView view, String url) {
Log.e("web", "load " + url + " finish");
super.onPageFinished(view, url);
}
@Override
public void onLoadResource(WebView view, String url) {
Log.e("web", "load " + url + " onLoadResource");
super.onLoadResource(view, url);
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Log.e("web", "load " + request.getUrl().toString() + " fionReceivedErrornish");
}
super.onReceivedError(view, request, error);
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.cancel();//应用代码更新为在服务器提供的证书符合您的预期时调用 SslErrorHandler.proceed(),否则调用 SslErrorHandler.cancel()。
super.onReceivedSslError(view, handler, error);
}
});
}
里面的几个方法一看命名就知道什么意思了,需要注意的是很多人对
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
view.loadUrl(request.getUrl().toString());
}
return true;
}
这个方法有误解,大多网上解释为:
而默认情况下,Android 系统会启动一个应用来处理被点击的链接,一般情况下默认浏览器会被启动来加载目标URL(或弹出浏览器选择菜单),网络上有很多博客都介绍到了,就是采用覆盖 WebViewClient 类的 shouldOverrideUrlLoading 方法来实现。
实际上:
1.如果没有提供 WebViewClient 对象,则 WebView 会请求 Activity 管理者选择合适的 URL 处理方式,一般情况就是启动浏览器来加载URL;
2.如果提供了 WebViewClient 对象且shouldOverrideUrlLoading 方法返回 true,则主机应用(意思应该是 Android 系统)处理URL;
3.如果提供了 WebViewClient 对象且shouldOverrideUrlLoading 方法返回 false,则当前 WebView 处理URL;
可参考:http://blog.csdn.net/zhyh1986/article/details/42169159
还有就是onReceivedSslError在使用时的安全问题
看下面的Log输出:
E/web: load https://www.baidu.com/ start
E/web: load https://www.baidu.com/ onLoadResource
E/web: load https://hpd.baidu.com/v.gif?tid=365&funcSta=whiteScreenEx&sourceSta=wiseindex&actionSta=start&logid=3393602869&ssid=0&ct=1&cst=9&logFrom=mid_news&logInfo=stability onLoadResource
E/web: load https://m.baidu.com/static/index/plus/plus_logo.png onLoadResource
E/web: load https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/iconfont/iconfont_846ac7cd.woff onLoadResource
......
......
.....
E/web: load https://s.bdstatic.com/common/openjs/bdbanner.js?bd-reform-version=2017101715 onLoadResource
E/web: load https://m.baidu.com/static/index/plus/public/tab_news.png onLoadResource
E/web: load https://www.baidu.com/ finish
WebChromeClient
辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等等。
可以Android自己处理一些webView的页面交互。
/**
* 辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等等。
*
* @param webView webView
*/
private void setChromeWebView(WebView webView) {
webView.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
}
@Override
public void onReceivedTitle(WebView view, String title) {
Log.e(TAG, "onReceivedTitle: " + title);
super.onReceivedTitle(view, title);
}
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
//自己处理javascript的警告框
// result.cancel();
// result.confirm();
return super.onJsAlert(view, url, message, result);
}
//支持javascript的确认框
@Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
new AlertDialog.Builder(WebViewActivity.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;
}
//支持javascript输入框
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
//自己处理message
// result.cancel(); 取消
// result.confirm(); 确认
return true;
}
});