一.简介
WebView是一个基于webkit引擎、展现web页面的控件。Android的Webview在低版本和高版本采用了不同的webkit版本内核,4.4后直接使用了Chrome。WebView用来显示和渲染Web页面,可直接使用html文件(网络上或本地assets中)作布局,也可和JavaScript交互调用。WebView控件功能强大,除了具有一般View的属性和设置外,还可以对url请求、页面加载、渲染、页面交互进行强大的处理。
一般来说Webview可单独使用,也可联合其工具类一起使用。
二.Webview常用方法
1.加载url方法
<1> 加载在线的html
webView.loadUrl("https://blog.csdn.net/weixin_37730482");
<2> 加载本地assets文件夹下的html
webView.loadUrl("file:///android_asset/hhh.html");
<3> 加载html片段
webView.loadData(context, "text/html", "uft-8");
加载html片段举例
html片段
String content ="<p><img src=\"http://XXXXXX/Upload/avatar/a025fe93cb5d401ead309a822707855e1516155901591.png_bak.png\" />\n"+
"\n"+
"\n"+
"先说第一个,如何绘制波浪图形。绘制波浪图形的方法有很多,这里介绍一种最简单的方法,就是使用canvas的drawLine方法绘制直线。我们可以将view的宽度转化成弧度,通过sin或者cos方法获取每个像素点的坐标,通过drawline绘制一条从顶点到底部的直线,这样都可以达到效果。\n"+
"\n"+
"\n"+
"再说第二个,这个是一个难点,但是实现起来却很简单。我们获取的坐标是从0-360度的坐标,也就是说,最后一个的坐标接下来的坐标应该是第一的坐标,它们是一个连续的没有断开的坐标系列,那么我们只需要将坐标按照一定的规则交换一下位置就可以实现波浪的荡漾效果了。\n"+
"\n"+
"\n"+
"<img src=\"http://XXXXXX/Upload/avatar/88e1cea03011497faa93f7c15fac81b31514426860951.png_bak.png\" />\n"+
"\n"+
"\n"+
"阿迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发<img src=\"http://XXXXXX/Upload/avatar/9bed29f2dee94d8ba6265f949c094fed1514878987457.png_bak.png\" />迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发迪斯发多发\n"+
"\n"+
"\n"+
"\n"+
"</p>\n"+
"<p><font color='red'>先说第一个,如何绘制波浪图形。绘制波浪图形的方法有很多,这里介绍一种最简单的方法,就是使用canvas的drawLine方法绘制直线。我们可以将view的宽度转化成弧度,通过sin或者cos方法获取每个像素点的坐标,通过drawline绘制一条从顶点到底部的直线,这样都可以达到效果。\n"+
"\n"+
"再说第二个,这个是一个难点,但是实现起来却很简单。我们获取的坐标是从0-360度的坐标,也就是说,最后一个的坐标接下来的坐标应该是第一的坐标,它们是一个连续的没有断开的坐标系列,那么我们只需要将坐标按照一定的规则交换一下位置就可以实现波浪的荡漾效果了。</font></p>";
样式
String linkCss ="<style type=\"text/css\"> "+
"img {" +
"width:100%;" +
"height:auto;" +
"}" +
"body {" +
"margin-right:15px;" +
"margin-left:15px;" +
"margin-top:15px;" +
"font-size:15px;" +
"}" +
"</style>";
加载
String html ="<html><header>"+ linkCss + "</header>" + content +"</body></html>";
webView.loadData(html, "text/html", "uft-8");
<4> 重新加载
mWebView.reload();
2.后退或是前进方法
<1> 页面是否可以后退方法
boolean b=webView.canGoBack();
<2> 页面后退方法
webView.goBack();
<3> 页面是否可以前进方法
boolean b=webView.canGoForward();
<4> 页面前进方法
webView.goForward();
<5> 页面前进或是后退方法
webView.goBackOrForward(steps);
steps:负数后退 正数则为前进。
<6> 逐步返回页面
package com.wjn.customwebviewjs;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import java.io.IOException;
public class WebViewBaseActivity extends AppCompatActivity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_webviewbase);
initView();
}
/**
* 初始化各种View
*/
private void initView() {
webView = findViewById(R.id.activity_activity_webviewbase_webview);
//设置WebSettings
WebViewSettingsUtils.setWebSettings(webView);
//添加WebViewClient事件
webView.setWebViewClient(new MyWebViewClient());
//加载Url
webView.loadUrl("https://blog.csdn.net/weixin_37730482");
}
/**
* WebViewClient监听
*/
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;//本APP处理接下来的H5页面加载而不是转到浏览器
}
}
/**
* onKeyDown方法
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (webView.canGoBack()) {
webView.goBack();
} else {
finish();
}
return true;
}
return super.onKeyDown(keyCode, event);
}
}
3.状态方法
<1> 激活WebView为活跃状态,能正常执行页面的响应
webView.onResume();
<2> 当页面失去焦点被切换到后台不可见状态,需要执行onPause方法 通知内核暂停所有动作,比如JavaScript执行。
webView.onPause();
<3> 当应用程序(存在WebView)被切换到后台,暂停WebView的所有操作。降低CPU功耗。
webView.pauseTimers();
<4> 恢复WebView状态
webView.resumeTimers();
<5> 销毁WebView 在关闭Activity时,如果WebView的音乐或是视频仍在播放,就必须销毁WebView。
webView.destroy();
如果WebView是动态添加到某个ViewGroup中,还需要在销毁WebView之前,将WebView移除容器。
linearLayout.removeView(webView);
webView.destroy();
4.WebView清除缓存方法
<1> 清除整个应用的缓存
webView.clearCache(true);
<2> 清除当前页面缓存
webView.clearHistory();
<3> 清除自动完成填充的表单数据
webView.clearFormData();
<4> 设置WebView缓存
当加载html页面时,WebView会在/data/data/包名目录下生成 database 与 cache 两个文件夹,而请求的 URL记录保存在 WebViewCache.db,而 URL的内容是保存在 WebViewCache 文件夹下。
设置缓存
webView.getSettings().setCacheMode(mode);
mode取值及意义
WebSettings.LOAD_CACHE_ONLY:不适用网络,只读取本地缓存数据。
WebSettings.LOAD_NO_CACHE:不适用缓存,只能从网络获取数据。
WebSettings.LOAD_CACHE_ELSE_NETWORK:只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。
WebSettings.LOAD_DEFAULT:(默认)根据cache-control决定是否从网络上取数据。
总结
根据以上两种模式,建议缓存策略为,判断是否有网络,有网话,使用LOAD_DEFAULT,无网络时,使用LOAD_CACHE_ELSE_NETWORK。
注意
每个 Application 只调用一次 WebSettings.setAppCachePath()和WebSettings.setAppCacheMaxSize()。
Demo
package com.wjn.customwebviewjs;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import java.io.File;
import java.io.IOException;
public class WebViewBaseActivity extends AppCompatActivity {
private WebView webView;
private WebSettings settings;
private File cacheDir;//WebView缓存文件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_webviewbase);
initView();
}
/**
* 初始化各种View
*/
private void initView() {
webView = findViewById(R.id.activity_activity_webviewbase_webview);
//设置WebSettings
settings = WebViewSettingsUtils.setWebSettings(webView);
//缓存数据
saveData(settings);
//添加WebViewClient事件
webView.setWebViewClient(new MyWebViewClient());
//加载Url
webView.loadUrl("https://blog.csdn.net/weixin_37730482");
}
/**
* HTML5数据存储
*/
private void saveData(WebSettings mWebSettings) {
if (null == mWebSettings) {
return;
}
if (NetHelperUtils.isNetworkConnected(this)) {
//根据cache-control决定是否从网络上取数据。
mWebSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
} else {
//没网,则从本地获取,即离线加载
mWebSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
}
cacheDir = getCacheDir();
if (cacheDir != null) {
String appCachePath = cacheDir.getAbsolutePath();
mWebSettings.setDomStorageEnabled(true);
mWebSettings.setDatabaseEnabled(true);
mWebSettings.setAppCacheEnabled(true);
mWebSettings.setAppCachePath(appCachePath);
Log.d("TAG", "appCachePath----:" + appCachePath);
}
}
/**
* WebViewClient监听
*/
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;//本APP处理接下来的H5页面加载而不是转到浏览器
}
}
/**
* onKeyDown方法
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (webView.canGoBack()) {
webView.goBack();
} else {
finish();
}
return true;
}
return super.onKeyDown(keyCode, event);
}
}
三. WebViewClient类
1.作用
处理各种通知 & 请求事件
2. 常见方法
<1> shouldOverrideUrlLoading()
作用:再次打开网页时是调用浏览器还是在本WebView中显示。
调用浏览器
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;//接下来的H5页面转到浏览器
}
}
本WebView中显示
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;//本APP处理接下来的H5页面加载而不是转到浏览器
}
}
<2> onPageStarted()
作用:开始载入页面调用的。
<3> onPageFinished()
作用:在页面加载结束时调用。
/**
* WebViewClient监听
*/
private class MyWebViewClient extends WebViewClient {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
}
}
<4> onLoadResource()
作用:在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。
<5> onReceivedError()
作用:加载页面的服务器出现错误时(如404)调用。
package com.wjn.customwebviewjs;
import android.graphics.Bitmap;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import java.io.File;
import java.io.IOException;
public class WebViewBaseActivity extends AppCompatActivity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_webviewbase);
initView();
}
/**
* 初始化各种View
*/
private void initView() {
webView = findViewById(R.id.activity_activity_webviewbase_webview);
//设置WebSettings
WebViewSettingsUtils.setWebSettings(webView);
//添加WebViewClient事件
webView.setWebViewClient(new MyWebViewClient());
//加载Url
webView.loadUrl("https://abc/XXX");
}
/**
* WebViewClient监听
*/
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;//本APP处理接下来的H5页面加载而不是转到浏览器
}
/**
* 已过时 (但仍可使用)
*/
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
Log.d("TAG", "已过时 6.0以下使用errorCode----:" + errorCode);
Log.d("TAG", "已过时 6.0以下使用description----:" + description);
Log.d("TAG", "已过时 6.0以下使用failingUrl----:" + failingUrl);
setErrorPage(view);// 加载自定义错误页面
}
/**
* 6.0以上使用
*/
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
int statusCode = error.getErrorCode();
String description = error.getDescription().toString();
Log.d("TAG", "statusCode----:" + statusCode);
Log.d("TAG", "description----:" + description);
setErrorPage(view);// 加载自定义错误页面
}
}
/**
* 自定义错误页面
*/
private void setErrorPage(WebView view) {
if (null == view) {
return;
}
view.loadUrl("about:blank");// 避免出现默认的错误界面
String mErrorUrl = "file:///android_asset/hhh.html";
view.loadUrl(mErrorUrl);
}
}
以上两个重载的方法写一个即可,虽然有一个已经过期,但也可使用。
<6> onReceivedSslError()
作用:处理https请求
package com.wjn.customwebviewjs;
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.webkit.SslErrorHandler;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import java.io.File;
import java.io.IOException;
public class WebViewBaseActivity extends AppCompatActivity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_webviewbase);
initView();
}
/**
* 初始化各种View
*/
private void initView() {
webView = findViewById(R.id.activity_activity_webviewbase_webview);
//设置WebSettings
WebViewSettingsUtils.setWebSettings(webView);
//添加WebViewClient事件
webView.setWebViewClient(new MyWebViewClient());
//加载Url
webView.loadUrl("https://blog.csdn.net/weixin_37730482");
}
/**
* WebViewClient监听
*/
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;//本APP处理接下来的H5页面加载而不是转到浏览器
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
super.onReceivedSslError(view, handler, error);
handler.proceed();//继续使用SSL证书 Proceed with the SSL certificate
handler.cancel();//取消这个请求和所有有错误的WebView挂起的请求 Cancel this request and all pending requests for the WebView that had the error
}
}
}
四.WebChromeClient类
1.作用
辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等等。
2.常见方法
<1> onProgressChanged()
作用:获得网页的加载进度并显示。
private class MyWebChromeClient extends WebChromeClient{
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
}
}
<2> onReceivedTitle()
作用:获取Web页中的标题。
<3> onReceivedIcon()
作用:获取Web页中的图标。
package com.wjn.customwebviewjs;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ImageView;
import android.widget.TextView;
public class WebViewBaseActivity extends AppCompatActivity {
private WebView webView;
private TextView textView;
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_webviewbase);
initView();
}
/**
* 初始化各种View
*/
private void initView() {
webView = findViewById(R.id.activity_activity_webviewbase_webview);
//设置WebSettings
WebViewSettingsUtils.setWebSettings(webView);
//添加WebViewClient事件
webView.setWebViewClient(new MyWebViewClient());
//添加WebChromeClient事件
webView.setWebChromeClient(new MyWebChromeClient());
//加载Url
webView.loadUrl("https://blog.csdn.net/weixin_37730482");
}
/**
* WebViewClient监听
*/
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;//本APP处理接下来的H5页面加载而不是转到浏览器
}
}
/**
* WebChromeClient监听
*/
private class MyWebChromeClient extends WebChromeClient {
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
textView.setText(title);
}
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
super.onReceivedIcon(view, icon);
imageView.setImageBitmap(icon);
}
}
}
<4> onJsAlert()
作用:支持javascript的警告框
<5> onJsConfirm()
作用:支持javascript的确认框
<6> onJsPrompt()
作用:支持javascript输入框
package com.wjn.customwebviewjs;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
public class WebViewBaseActivity extends AppCompatActivity {
private WebView webView;
private TextView textView;
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_webviewbase);
initView();
}
/**
* 初始化各种View
*/
private void initView() {
webView = findViewById(R.id.activity_activity_webviewbase_webview);
//设置WebSettings
WebViewSettingsUtils.setWebSettings(webView);
//添加WebViewClient事件
webView.setWebViewClient(new MyWebViewClient());
//添加WebChromeClient事件
webView.setWebChromeClient(new MyWebChromeClient());
//加载Url
webView.loadUrl("https://blog.csdn.net/weixin_37730482");
}
/**
* WebViewClient监听
*/
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;//本APP处理接下来的H5页面加载而不是转到浏览器
}
}
/**
* WebChromeClient监听
*/
private class MyWebChromeClient extends WebChromeClient {
/**
* onJsAlert方法 拦截JS的alert对话框
*/
@Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
//创建一个Builder来显示网页中的对话框
new AlertDialog.Builder(WebViewBaseActivity.this)
.setTitle("Alert对话框")
.setMessage(message)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setCancelable(false).show();
return true;
}
/**
* onJsConfirm方法 拦截JS的confirm对话框
*/
@Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
new AlertDialog.Builder(WebViewBaseActivity.this)
.setTitle("Confirm对话框")
.setMessage(message)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
}).setCancelable(false).show();
return true;
}
/**
* onJsPrompt方法 拦截JS的prompt对话框
*/
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, final JsPromptResult result) {
//①获得一个LayoutInflater对象factory,加载指定布局成相应对象
final LayoutInflater inflater = LayoutInflater.from(WebViewBaseActivity.this);
final View myview = inflater.inflate(R.layout.prompt_view, null);
//设置TextView对应网页中的提示信息,edit设置来自于网页的默认文字
((TextView) myview.findViewById(R.id.textview)).setText(message);
((EditText) myview.findViewById(R.id.edittext)).setText(defaultValue);
//定义对话框上的确定按钮
new AlertDialog.Builder(WebViewBaseActivity.this).setTitle("Prompt对话框").setView(myview)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//单击确定后取得输入的值,传给网页处理
String value = ((EditText) myview.findViewById(R.id.edittext)).getText().toString();
result.confirm(value);
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
}).show();
return true;
}
}
}
五.添加UserAgent
package com.wjn.customwebviewjs;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class WebViewBaseActivity extends AppCompatActivity {
private LinearLayout linearLayout;
private WebView webView;
private WebSettings settings;
private String Add_AGENT = "add_AGENT";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_webviewbase);
initView();
}
/**
* 初始化各种View
*/
private void initView() {
linearLayout = findViewById(R.id.activity_webviewbaselayout);
webView = new WebView(getApplicationContext());
linearLayout.addView(webView);
//设置WebSettings
settings = WebViewSettingsUtils.setWebSettings(webView);
//添加代理
setUserAgent(settings);
//加载Url
webView.loadUrl("https://blog.csdn.net/weixin_37730482");
}
/**
* 设置代理
*/
private void setUserAgent(WebSettings settings) {
if (null == settings) {
return;
}
String ua1 = settings.getUserAgentString();
Log.d("TAG", "默认ua1----:" + ua1);
settings.setUserAgentString(ua1 + " " + Add_AGENT + " " + Add_AGENT);
String ua2 = settings.getUserAgentString();
Log.d("TAG", "操作后ua2----:" + ua2);
}
/**
* onDestroy方法
*/
@Override
protected void onDestroy() {
super.onDestroy();
if (webView != null) {
webView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
((ViewGroup) webView.getParent()).removeView(webView);
webView.destroy();
webView = null;
}
}
}
六.WebView内存泄露
使用WebView时,如何避免WebView内存泄露呢
1.不在xml中定义 Webview ,而是在需要的时候在Activity中创建。并且Context使用 getApplicationgContext()
2.在 Activity 销毁( WebView )的时候,先让 WebView 加载null内容,然后移除 WebView,再销毁 WebView,最后置空。
package com.wjn.customwebviewjs;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class WebViewBaseActivity extends AppCompatActivity {
private LinearLayout linearLayout;
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_webviewbase);
initView();
}
/**
* 初始化各种View
*/
private void initView() {
linearLayout = findViewById(R.id.activity_webviewbaselayout);
webView = new WebView(getApplicationContext());
linearLayout.addView(webView);
//设置WebSettings
WebViewSettingsUtils.setWebSettings(webView);
//加载Url
webView.loadUrl("https://blog.csdn.net/weixin_37730482");
}
/**
* onDestroy方法
*/
@Override
protected void onDestroy() {
super.onDestroy();
if (webView != null) {
webView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
((ViewGroup) webView.getParent()).removeView(webView);
webView.destroy();
webView = null;
}
}
}
附:WebView官方文档:http://androiddoc.qiniudn.com/reference/android/webkit/WebView.html
最后附webview settings的一些常用属性
WebSettings webSettings=webView.getSettings();
1.setAllowContentAccess (boolean allow)
是否允许在WebView中访问内容URL(Content Url),默认允许。内容Url访问允许WebView从安装在系统中的内容提供者载入内容。
2.setAllowFileAccess (boolean allow)
是否允许访问文件,默认允许。注意,这里只是允许或禁止对文件系统的访问,Assets 和 resources 文件使用file:///android_asset和file:///android_res仍是可访问的。
3.setAllowFileAccessFromFileURLs (boolean flag)
是否允许运行在一个URL环境(the context of a file scheme URL)中的JavaScript访问来自其他URL环境的内容,为了保证安全,应该不允许。也请注意,这项设置只影响对file schema 资源的JavaScript访问,其他形式的访问,例如来自图片HTML单元的访问不受影响。为了防止相同的域策略(same domain policy)对ICE_CREAM_SANDWICH以及更老机型的侵害,应该显式地设置此值为false。
4.setAllowUniversalAccessFromFileURLs (boolean flag)
是否允许运行在一个file schema URL环境下的JavaScript访问来自其他任何来源的内容,包括其他file schema URLs. 参见setAllowFileAccessFromFileURLs(boolean),为了确保安全,应该设置为不允许,注意这项设置只影响对file schema 资源的JavaScript访问,其他形式的访问,例如来自图片HTML单元的访问不受影响。为了防止相同的域策略(same domain policy)对ICE_CREAM_SANDWICH以及更老机型的侵害,应该显式地设置此值为false。ICE_CREAM_SANDWICH_MR1 以及更老的版本此默认值为true,JELLY_BEAN以及更新版本此默认值为false
5.setAppCacheEnabled (boolean flag)
应用缓存API是否可用,默认值false, 结合setAppCachePath(String)使用。
6.setAppCachePath(String)
设置应用缓存文件的路径。为了让应用缓存API可用,此方法必须传入一个应用可写的路径。该方法只会执行一次,重复调用会被忽略。
7.setAppCacheMaxSize (long appCacheMaxSize)
已废弃。设置应用缓存内容的最大值。所传值会被近似为数据库支持的最近似值,因此这是一个指示值,而不是一个固定值。所传值若小于数据库大小不会让数据库调整大小。默认值是MAX_VALUE,建议将默认值设置为最大值。
8.setBlockNetworkImage (boolean flag)
是否禁止从网络(通过http和https URI schemes访问的资源)下载图片资源,默认值为false。注意,除非getLoadsImagesAutomatically()返回true,否则该方法无效。还请注意,即使此项设置为false,使用
9.setBlockNetworkLoads(boolean)禁止所有网络加载也会阻止网络图片的加载。当此项设置的值从true变为false,WebView当前显示的内容所引用的网络图片资源会自动获取。
10.setBlockNetworkLoads (boolean flag)
是否禁止从网络下载数据,如果app有INTERNET权限,默认值为false,否则默认为true。使用setBlockNetworkImage(boolean) 只会禁止图片资源的加载。注意此值由true变为false,当前WebView展示的内容所引用的网络资源不会自动加载,直到调用了重载。如果APP没有INTERNET权限,设置此值为false会抛出SecurityException。
11.setBuiltInZoomControls (boolean enabled)
是否使用内置的缩放机制。内置的缩放机制包括屏幕上的缩放控件(浮于WebView内容之上)和缩放手势的运用。通过setDisplayZoomControls(boolean)可以控制是否显示这些控件,默认值为false。
12.setCacheMode (int mode)
重写使用缓存的方式,默认值LOAD_DEFAULT。缓存的使用方式基于导航类型,正常的页面加载,检测缓存,需要时缓存内容复现。导航返回时,内容不会复现,只有内容会从缓存盘中恢复。该方法允许客户端通过指定LOAD_DEFAULT, LOAD_CACHE_ELSE_NETWORK, LOAD_NO_CACHE or LOAD_CACHE_ONLY的其中一项来重写其行为。
13.setCursiveFontFamily (String font)
设置WebView字体库字体,默认“cursive”
14.setDatabaseEnabled (boolean flag)
数据库存储API是否可用,默认值false。如何正确设置数据存储API参见setDatabasePath(String)。该设置对同一进程中的所有WebView实例均有效。注意,只能在当前进程的任意WebView加载页面之前修改此项,因为此节点之后WebView的实现类可能会忽略该项设置的改变。
15.setDatabasePath (String databasePath)
已废弃,数据库路径由实现(implementation)管理,调用此方法无效。
设置数据库的存储路径,为了保证数据库正确运行,该方法必须使用一个应用可写的路径。此方法只能执行一次,重复调用会被忽略。
16.setDefaultFixedFontSize (int size)
设置默认固定的字体大小,默认为16,可取值1到72
17.setDefaultFontSize (int size)
设置默认的字体大小,默认16,可取值1到72
18.setDefaultTextEncodingName (String encoding)
设置默认的字符编码集,默认”UTF-8”.
19.setDefaultZoom (WebSettings.ZoomDensity zoom)
已废弃。设置默认的缩放密度,必须在UI线程调用,默认值MEDIUM.该项设置在新应用中不推荐使用。如果WebView用于展示手机页面,可以通过调整页面的’meta viewport’ 标记中的’width’ 和 ‘initial-scale’属性实现预期效果,对于漏用标记的页面,可以使用setInitialScale(int)和setUseWideViewPort(boolean) .
20.setDisplayZoomControls (boolean enabled)
使用内置的缩放机制时是否展示缩放控件,默认值true。参见setBuiltInZoomControls(boolean).
21.setDomStorageEnabled (boolean flag)
DOM存储API是否可用,默认false。
22.setEnableSmoothTransition (boolean enable)
已废弃,将来会成为空操作(no-op),设置当panning或者缩放或者持有当前WebView的window没有焦点时是否允许其光滑过渡,若为true,WebView会选择一个性能最大化的解决方案。例如过渡时WebView的内容可能不更新。若为false,WebView会保持精度(fidelity),默认值false。
23.setFantasyFontFamily (String font)
设置fantasy字体集(font family)的名字默认为“fantasy”
24.setFixedFontFamily (String font)
设置固定的字体集的名字,默认为”monospace”。
25.setGeolocationDatabasePath (String databasePath)
定位数据库的保存路径,为了确保定位权限和缓存位置的持久化,该方法应该传入一个应用可写的路径。
26.setGeolocationEnabled (boolean flag)
定位是否可用,默认为true。请注意,为了确保定位API在WebView的页面中可用,必须遵守如下约定:
(1) app必须有定位的权限,参见ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION;
(2) app必须提供onGeolocationPermissionsShowPrompt(String, GeolocationPermissions.Callback)回调方法的实现,在页面通过JavaScript定位API请求定位时接收通知。
作为可选项,可以在数据库中存储历史位置和Web初始权限,参见setGeolocationDatabasePath(String).
27.setJavaScriptCanOpenWindowsAutomatically (boolean flag)
让JavaScript自动打开窗口,默认false。适用于JavaScript方法window.open()。
28.setJavaScriptEnabled (boolean flag)
设置WebView是否允许执行JavaScript脚本,默认false,不允许。
29.setLayoutAlgorithm (WebSettings.LayoutAlgorithm l)
设置布局,会引起WebView的重新布局(relayout),默认值NARROW_COLUMNS
30.setLightTouchEnabled (boolean enabled)
已废弃。从 JELLY_BEAN 开始,该设置无效。允许使用轻触摸做出选择和光标悬停。
31.setLoadWithOverviewMode (boolean overview)
是否允许WebView度超出以概览的方式载入页面,默认false。即缩小内容以适应屏幕宽度。该项设置在内容宽度超出WebView控件的宽度时生效,例如当getUseWideViewPort() 返回true时。
32.setLoadsImagesAutomatically (boolean flag)
WebView是否下载图片资源,默认为true。注意,该方法控制所有图片的下载,包括使用URI嵌入的图片(使用setBlockNetworkImage(boolean) 只控制使用网络URI的图片的下载)。如果该设置项的值由false变为true,WebView展示的内容所引用的所有的图片资源将自动下载。
33.setMediaPlaybackRequiresUserGesture (boolean require)
WebView是否需要用户的手势进行媒体播放,默认值为true。
34.setMinimumFontSize (int size)
设置最小的字号,默认为8
35.setMinimumLogicalFontSize (int size)
设置最小的本地字号,默认为8。
36.setMixedContentMode (int mode)
当一个安全的来源(origin)试图从一个不安全的来源加载资源时配置WebView的行为。默认情况下,KITKAT及更低版本默认值为MIXED_CONTENT_ALWAYS_ALLOW,LOLLIPOP版本默认值MIXED_CONTENT_NEVER_ALLOW,WebView首选的最安全的操作模式为MIXED_CONTENT_NEVER_ALLOW ,不鼓励使用MIXED_CONTENT_ALWAYS_ALLOW。
37.setNeedInitialFocus (boolean flag)
调用requestFocus(int, Android.graphics.Rect)时是否需要设置节点获取焦点,默认值为true。
38.setOffscreenPreRaster (boolean enabled)
当WebView切换到后台但仍然与窗口关联时是否raster tiles,打开它可以避免在WebView从后台切换到前台时重新绘制,默认值false。在这种模式下后台的WebView占用更多的内存。请按如下准则显示内存的使用:
WebView的尺寸不能比设备的屏幕尺寸更大;
限制在少数WebView上使用该模式;
在可见的WebView和即将显现的WebView上使用;
setPluginState (WebSettings.PluginState state)
在API18以上已废弃。未来将不支持插件,不要使用。告诉WebView启用、禁用或者有即用(on demand)的插件,即用模式是指如果存在一个可以处理嵌入内容的插件,会显示一个占位图标,点击时开启。默认值OFF。
39.setRenderPriority (WebSettings.RenderPriority priority)
在API18以上已废弃。不建议调整线程优先级,未来版本不会支持这样做。设置绘制(Render,很多书上翻译成渲染,貌似很专业,但是不易懂,不敢苟同)线程的优先级。不像其他设置,同一进程中只需调用一次,默认值NORMAL。
40.setSansSerifFontFamily (String font)
设置无衬线字体集(sans-serif font family)的名字。默认值”sans-serif”.
41.setSaveFormData (boolean save)
WebView是否保存表单数据,默认值true。
42.setSavePassword (boolean save)
API18以上版本已废弃。未来版本将不支持保存WebView中的密码。设置WebView是否保存密码,默认true。
43.setSerifFontFamily (String font)
设置衬线字体集(serif font family)的名字,默认“sans-serif”。
44.setStandardFontFamily (String font)
设置标准字体集的名字,默认值“sans-serif”。
45.setSupportMultipleWindows (boolean support)
设置WebView是否支持多窗口。如果设置为true,主程序要实现onCreateWindow(WebView, boolean, boolean, Message),默认false。
46.setSupportZoom (boolean support)
WebView是否支持使用屏幕上的缩放控件和手势进行缩放,默认值true。设置setBuiltInZoomControls(boolean)可以使用特殊的缩放机制。该项设置不会影响zoomIn() and zoomOut()的缩放操作。
47.setTextSize (WebSettings.TextSize t)
API14版本以上已废弃。请取代使用setTextZoom(int)。设置页面文本的尺寸,默认NORMAL。
48.setTextZoom (int textZoom)
设置页面上的文本缩放百分比,默认100。
49.setUseWideViewPort (boolean use)
WebView是否支持HTML的“viewport”标签或者使用wide viewport。设置值为true时,布局的宽度总是与WebView控件上的设备无关像素(device-dependent pixels)宽度一致。当值为true且页面包含viewport标记,将使用标签指定的宽度。如果页面不包含标签或者标签没有提供宽度,那就使用wide viewport。
50.setUserAgentString (String ua)
设置WebView的用户代理字符串。如果字符串为null或者empty,将使用系统默认值。注意从KITKAT版本开始,加载网页时改变用户代理会让WebView再次初始化加载。
51.supportMultipleWindows ()
获取WebView是否支持多窗口的值。
52.supportZoom ()
获取WebView是否支持缩放的值