WebView是Android系统中的原生控件,其主要功能与前端页面进行响应交互,快捷省时地实现如期的功能,相当于增强版的内置浏览器。
WebView能做些什么?主要是提供了一个加载H5的控件~可根据需求来配置相关功能。基本使用如下:
布局文件中添加:
<WebView
android:id="@+id/id_webview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
相关权限设置:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
java文件中调用:
WebView itWebview = findviewbyId(R.id.id_webview);
itWebview.loadUrl("https://m.baidu.com");
这样就加载一个网络连接了,加载本地连接如下:
//打开本包内asset目录下的test.html文件
wView.loadUrl(" file:///android_asset/test.html ");
//打开本地sd卡内的index.html文件
wView.loadUrl("content://com.android.htmlfileprovider/sdcard/index.html");
//打开指定URL的html文件
wView.loadUrl(" http://m.baidu.com");
以上是简单的使用。想要完全掌握使用webview,还得深入去了解webview的相关组成。WebView这个控件又包含四大部分:WebSettings、WebViewClient、WebChromeClient、JavascriptInterface。通过四个类,我们可以为WebView设置基础功能和监听,下面会逐一介绍四个类的方法。除了这四部分,WebView还有自己的API,先来介绍WebView的API。
// 加载url:
webView.loadUrl(url)
// 往请求头header增加参数
val hashMap: HashMap<String, String> = HashMap()
hashMap["name"] = "zhangsan"
webView.loadUrl(url, hashMap)
// 加载 HTML 页面的一小段内容
webView.loadData("", "text/html", "utf-8")
webView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null)
// 后退、前进:
webView.canGoBack() //是否可以后退
webView.goBack() //后退一页面
webView.canGoForward() //是否可以前进
webView.goForward() //前进一页面
webView.goBackOrForward(-1) //后退或前进多少步,正前负退
//清除缓存数据:
// 清除网页访问留下的缓存,由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.
webView.clearCache(true)
// 清除当前webview访问的历史记录,只会webview访问历史记录里的所有记录除了当前访问记录.
webView.clearHistory()
// 这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据。
webView.clearFormData()
//WebView的状态
webView.onResume() // 可见状态
webView.onPause() // 页面失去焦点变成不可见状态
webView.pauseTimers() // 页面失去焦点变成不可见状态,对整个应用的webview起作用
webView.resumeTimers() //恢复pauseTimers时的动作
webView.destroy() //销毁
- WebSettings 用于webview的相关设置、配置项,如缓存、自适应屏幕、缩放、js支持等,如下:
WebSettings webSettings = itWebview.getSettings();
//如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
webSettings.setJavaScriptEnabled(true);
// 若加载的 html 里有JS 在执行动画等操作,会造成资源浪费(CPU、电量)
// 在 onStop 和 onResume 里分别把 setJavaScriptEnabled() 给设置成 false 和 true 即可
//设置自适应屏幕,两者合用
webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小
webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小
//缩放操作
webSettings.setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。
webSettings.setBuiltInZoomControls(true); //设置内置的缩放控件。若为false,则该WebView不可缩放
webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件
//其他细节操作
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE); //关闭webview中缓存
webSettings.setAllowFileAccess(true); //设置可以访问文件
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式
WebViewClient :处理各种通知和事件,如页面开始,页面加载结束,error,重定向等,其中用的最多的是shouldOverrideUrlLoading、onPageStarted、onPageFinished
itWebview.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//在网页上的所有加载都经过这个方法
//比如在本地WebView加载H5,而不是浏览器
return super.shouldOverrideUrlLoading(view, url);
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return super.shouldOverrideUrlLoading(view, request);
}
@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);
}
@Override
public void onLoadResource(WebView view, String url) {
// 在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。
super.onLoadResource(view, url);
}
@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
// 拦截替换网络请求数据
return super.shouldInterceptRequest(view, request);
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
// (报告错误信息,当加载出错的时候会回调此方法)
super.onReceivedError(view, request, error);
}
@Override
public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
//重写此方法才能够处理在浏览器中的按键事件。
return super.shouldOverrideKeyEvent(view, event);
}
@Override
public void onScaleChanged(WebView view, float oldScale, float newScale) {
// (WebView缩放大小发生改变时调用)
super.onScaleChanged(view, oldScale, newScale);
}
});
在android 7.0系统以上 已经摒弃了shouldOverrideUrlLoading(WebView view, String url)此方法,所以,如果要拦截URL,我们需要做兼容性处理,重写shouldOverrideUrlLoading(WebView view, WebResourceRequest request)方法,获取得到的可正常使用的URL。shouldOverrideUrlLoading(WebView view, WebResourceRequest request)是可以通过request.getUrl()获取到WebView需要加载的地址,然后通过shouldOverrideUrlLoading(WebView view, String url)此方法显示加载。
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
view.loadUrl(request.getUrl().toString());
} else {
view.loadUrl(request.toString());
}
return true;
}
一般 会用该接口实现 shouldOverrideUrlLoading,用于处理拦截url和内部加载
itWebview.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// 后续的条子只在本webview中进行,不会跳转到外部的浏览器
//H5调起微信app支付方法二(可使用)
if (url.startsWith("weixin://wap/pay?")) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
startActivity(intent);
return true;
}
if(url.startsWith("alipays:") || url.startsWith("alipay")) {
try {
startActivity(new Intent("android.intent.action.VIEW", Uri.parse(url)));
} catch (Exception e) {
new AlertDialog.Builder(WebActivity.this)
.setMessage("未检测到支付宝客户端,请安装后重试。")
.setPositiveButton("立即安装", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Uri alipayUrl = Uri.parse("https://d.alipay.com");
startActivity(new Intent("android.intent.action.VIEW", alipayUrl));
}
}).setNegativeButton("取消", null).show();
}
return true;
}
if (!(url.startsWith("http") || url.startsWith("https"))) {
return true;
}
view.loadUrl(url);
return false;
}
});
WebChromeClient :
内核处理类,主要用于网站的加载进度、标题、图片文件选择、JS弹窗
itWebview.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
// 网页加载进度
super.onProgressChanged(view, newProgress);
}
@Override
public void onReceivedTitle(WebView view, String title) {
// 网页title
super.onReceivedTitle(view, title);
}
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
// 网页图标
super.onReceivedIcon(view, icon);
}
@Override
public void onCloseWindow(WebView window) {
// 窗口关闭
super.onCloseWindow(window);
}
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
// JS交互确认框
return super.onJsConfirm(view, url, message, result);
}
@Override
public void onPermissionRequest(PermissionRequest request) {
super.onPermissionRequest(request);
}
@Override
public void onPermissionRequestCanceled(PermissionRequest request) {
super.onPermissionRequestCanceled(request);
}
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
// 调用的文件选择器
return super.onShowFileChooser(webView, filePathCallback, fileChooserParams);
}
});
JavascriptInterface: 可以通过addJavascriptInterface()设置JavascriptInterface,从而使JS可以直接调用JavascriptInterface设置好的方法,比如H5想要跳转Activity、打开原生视频等都可以通知App。
webview
1. 通过JS调用Android原生代码
itWebview.addJavascriptInterface(new H5BridgeInterface(H5WebActivity.this), "H5BridgeInterface");
H5WebActivity相关代码
package cn.zeus.jondy.h5;
import android.app.DownloadManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.PersistableBundle;
import android.webkit.DownloadListener;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.SslErrorHandler;
import android.webkit.URLUtil;
import android.webkit.WebChromeClient;
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 androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import cn.zeus.jondy.R;
import cn.zeus.jondy.utils.Lg;
public class H5WebActivity extends AppCompatActivity {
private static final String TAG = H5WebActivity.class.getSimpleName();
private static final String webUrl = "file:///android_asset/h5/test.html";
private WebView itWebview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Lg.d("onCreate ---");
setContentView(R.layout.activity_web);
itWebview = findViewById(R.id.it_webview);
initWebview();
}
private void initWebview() {
Lg.d("initWebview ---");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
itWebview.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
WebSettings webSettings = itWebview.getSettings();
//如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
webSettings.setJavaScriptEnabled(true);
// 若加载的 html 里有JS 在执行动画等操作,会造成资源浪费(CPU、电量)
// 在 onStop 和 onResume 里分别把 setJavaScriptEnabled() 给设置成 false 和 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.setCacheMode(WebSettings.LOAD_NO_CACHE); //关闭webview中缓存
webSettings.setAllowFileAccess(true); //设置可以访问文件
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式
itWebview.loadUrl(webUrl);
itWebview.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {//使用WebView加载显示url
view.loadUrl(url);
//返回true
return true;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
Lg.e("onPageStarted :---"+url);
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
Lg.e("onPageFinished :---"+url);
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
Lg.e("onReceivedError :---"+failingUrl);
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
}
@Override
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
super.onReceivedHttpError(view, request, errorResponse);
Lg.e("onReceivedError :---"+errorResponse.getStatusCode());
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
super.onReceivedSslError(view, handler, error);
Lg.e("onReceivedError :---"+error.getUrl());
}
});
itWebview.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
Lg.d("onProgressChanged :---"+newProgress);
}
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
}
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
return super.onJsAlert(view, url, message, result);
}
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
return super.onJsConfirm(view, url, message, result);
}
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
return super.onJsPrompt(view, url, message, defaultValue, result);
}
});
itWebview.addJavascriptInterface(new H5BridgeInterface(H5WebActivity.this), "H5BridgeInterface");
itWebview.setDownloadListener(new DownloadListener() {
@Override
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
// startDownload(url);
Lg.d("download ,url :" + url);
Lg.d("download ,mimetype :" + mimetype);
Lg.d("download ,contentDisposition :" + contentDisposition);
downloadBySystem(url, contentDisposition, mimetype);
}
});
}
private void downloadBySystem(String url, String contentDisposition, String mimeType) {
// 指定下载地址
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
// 允许媒体扫描,根据下载的文件类型被加入相册、音乐等媒体库
request.allowScanningByMediaScanner();
// 设置通知的显示类型,下载进行时和完成后显示通知
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
// 设置通知栏的标题,如果不设置,默认使用文件名
// request.setTitle("This is title");
// 设置通知栏的描述
// request.setDescription("This is description");
// 允许在计费流量下下载
request.setAllowedOverMetered(false);
// 允许该记录在下载管理界面可见
request.setVisibleInDownloadsUi(false);
// 允许漫游时下载
request.setAllowedOverRoaming(true);
// 允许下载的网路类型
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
// 设置下载文件保存的路径和文件名
if (mimeType.equalsIgnoreCase("application/octet-stream")) {
mimeType = "image/jpeg";
}
request.setMimeType(mimeType);
String fileName = URLUtil.guessFileName(url, contentDisposition, mimeType);
Lg.d("download fileName :" + fileName);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
// 另外可选一下方法,自定义下载路径
// request.setDestinationUri()
// request.setDestinationInExternalFilesDir()
final DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
// 添加一个下载任务
long downloadId = downloadManager.enqueue(request);
Lg.d("download downloadId :" + downloadId);
}
}