WebView基础
Webview 基础
WebView 介绍
WebView 是一个基于 webkit 引擎、展现 web 页面的控件。
Android 的 Webview 在低版本和高版本采用了不同的 webkit 版本内核,4.4 后直接使用了 Chrome。
WebView 作用:
- 显示和渲染 Web 页面
- 直接使用 html 文件(网络上或本地 assets 中)作布局
- 可和 JavaScript 交互调用
WebView 控件功能强大,除了具有一般 View 的属性和设置外,还可以对 url 请求、页面加载、渲染、页面交互进行强大的处理。
Webview 常用方法
WebView 的状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 激活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();
关于前进 / 后退网页
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 是否可以后退
Webview.canGoBack()
// 后退网页
Webview.goBack()
// 是否可以前进
Webview.canGoForward()
// 前进网页
Webview.goForward()
// 以当前的index为起始点前进或者后退到历史记录中指定的steps;如果steps为负数则为后退,正数则为前进
Webview.goBackOrForward(intsteps)
- Android 中按 Back 键控制网页后退
1
2
3
4
5
6
7
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
清除缓存数据
1
2
3
4
5
6
7
8
// 清除网页访问留下的缓存;由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.
Webview.clearCache(true);
// 清除当前webview访问的历史记录,只会清除webview访问历史记录里的所有记录除了当前访问记录
Webview.clearHistory();
// 这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据
Webview.clearFormData();
设置滚动条
1
2
3
WebView.setHorizontalScrollBarEnabled(false); 水平滚动条不可用
WebView.setVerticalScrollBarEnabled(false); 竖直滚动条不可用
WebView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY); 滚动条在view里面,不占用位置
Webview 去掉滑动拖拽反馈 (边缘效应)
1
webView.setOverScrollMode(View.OVER_SCROLL_NEVER);
Webview 自适应屏幕
这方法可以让你的页面适应手机屏幕的分辨率,完整的显示在屏幕上,可以放大缩小。
1
2
3
WebSettings.setUseWideViewPort(true); // 如果没有设置为true,那么下面的网页在手机上显示不出来
// https://i.topeffects.cn/activity/index?id=495&spm=38.214.23.167#
WebSettings.setLoadWithOverviewMode(true);
WebView scrollbarStyle 属性
android:scrollbarStyle
可以定义滚动条的样式和位置,可选值有 insideOverlay、insideInset、outsideOverlay、outsideInset 四种。
其中 inside 和 outside 分别表示是否在 view 的 padding 区域内,overlay 和 inset 表示覆盖在 view 上或是插在 view 后面,所以四种值分别表示:
1
2
3
4
1. insideOverlay:默认值,表示在padding区域内并且覆盖在view上
2. insideInset:表示在padding区域内并且插入在view后面
3. outsideOverlay:表示在padding区域外并且覆盖在view上,推荐这个
4. outsideInset:表示在padding区域外并且插入在view后面
WebView 设置代理
[Android 为 WebView 设置代理访问网站 ZhouZhou Blog](https://zwc365.com/2021/07/12/android%E4%B8%BAwebview%E8%AE%BE%E7%BD%AE%E4%BB%A3%E7%90%86%E8%AE%BF%E9%97%AE%E7%BD%91%E7%AB%99) [Android的Webview使用代理访问网站的另一种实现 ZhouZhou Blog](https://zwc365.com/2020/11/11/android-webview-proxy) - GitHub - li520666/WebViewProxy: Class to set Android WebView proxy
WebView 常用类
WebSettings 对 WebView 进行配置和管理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 声明WebSettings子类
WebSettings webSettings = webView.getSettings();
// 如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
webSettings.setJavaScriptEnabled(true);
// 支持插件
webSettings.setPluginsEnabled(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.setAllowFileAccess(true); //设置可以访问文件
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式
设置 WebView 缓存
当加载 html 页面时,WebView 会在/data/data/包名目录下生成 database 与 cache 两个文件夹;请求的 URL 记录保存在 WebViewCache.db,而 URL 的内容是保存在 WebViewCache 文件夹下。是否启用缓存:
1
2
3
4
5
6
7
8
9
//优先使用缓存:
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);
案例:离线加载
1
2
3
4
5
6
7
8
9
10
11
12
if (NetStatusUtil.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 缓存目录
注意: 每个 Application 只调用一次 WebSettings.setAppCachePath(),WebSettings.setAppCacheMaxSize()
WebChromeClient 辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等等
WebChromeClient 主要处理解析,渲染网页等浏览器做的事情,辅助 WebView 处理 Javascript 的对话框,网站图标,网站 title,加载进度等
1
2
3
4
5
6
7
8
onCloseWindow(关闭WebView)
onCreateWindow()
onJsAlert (WebView上alert是弹不出来东西的,需要定制你的WebChromeClient处理弹出)
onJsPrompt
onJsConfirm
onProgressChanged
onReceivedIcon
onReceivedTitle
onProgressChanged 获得网页的加载进度并显示
1
2
3
4
5
6
7
8
9
10
11
webview.setWebChromeClient(new WebChromeClient(){
@Override
public void onProgressChanged(WebView view, int newProgress) {
if (newProgress < 100) {
String progress = newProgress + "%";
progress.setText(progress);
} else {
}
}
});
onReceivedTitle 获取 Web 页中的标题
1
2
3
4
5
6
webview.setWebChromeClient(new WebChromeClient(){
@Override
public void onReceivedTitle(WebView view, String title) {
titleview.setText(title);
}
}
WebViewClient 处理各种通知 & 请求事件
WebViewClient 是帮助 WebView 处理各种通知、请求事件的,具体来说包括:
1
2
3
4
5
6
shouldOverrideUrlLoading()
onLoadResource
onPageStart
onPageFinish
onReceiveError //这个就是我们想要的方法
onReceivedHttpAuthRequest
shouldOverrideUrlLoading()
打开网页时不调用系统浏览器, 而是在本 WebView 中显示;在网页上的所有加载都经过这个方法,这个函数我们可以做很多操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//步骤1. 定义Webview组件
Webview webview = (WebView) findViewById(R.id.webView1);
//步骤2. 选择加载方式
//方式1. 加载一个网页:webView.loadUrl("http://www.google.com/");
//方式2:加载apk包中的html页面
webView.loadUrl("file:///android_asset/test.html");
//方式3:加载手机本地的html页面
webView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");
//步骤3. 复写shouldOverrideUrlLoading()方法,使得打开网页时不调用系统浏览器, 而是在本WebView中显示
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
onPageStarted()/onPageFinished
- onPageStarted 开始载入页面调用的,我们可以设定一个 loading 的页面,告诉用户程序在等待网络响应。
- onPageFinished 在页面加载结束时调用。我们可以关闭 loading 条,切换程序动作。
1
2
3
4
5
6
7
8
9
10
webView.setWebViewClient(new WebViewClient(){
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// 设定加载开始的操作
}
@Override
public void onPageFinished(WebView view, String url) {
// 设定加载结束的操作
}
});
onLoadResource()
在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。
1
2
3
4
5
6
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean onLoadResource(WebView view, String url) {
// 设定加载资源的操作
}
});
onReceivedError() 定义 404 错误
加载页面的服务器出现错误时(如 404)调用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//步骤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;
}
}
});
WebView 自定义 404 错误,由于 android.webkit.WebViewClient
中 onReceivedError()
不能回调 http code 中 404 的错误,
但如果在 404 的 title 中有 404,可以利用 WebChromeClient 的 onReceivedTitle() 来判断 title 包含 404 来做处理,
不过主流的浏览器,uc,qq 等都没有处理 404 错误页面
- webview 定义错误页面(将错误页面放在 assets/,在这个回调方法中加载默认错误页面)
1
2
3
public void onReceivedError(WebView view, int errorCode,
String description, String failingUrl) {
}
onReceivedSslError() 处理 https 请求
webView 默认是不处理 https 请求的,页面显示空白,需要进行如下设置:
1
2
3
4
5
6
7
8
webView.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.proceed(); //表示等待证书响应
// handler.cancel(); //表示挂起连接,为默认方式
// handler.handleMessage(null); //可做其他处理
}
});
WebView 缓存
- https://github.com/yale8848/CacheWebView
- Android:手把手教你构建 全面的 WebView 缓存机制 & 资源加载方案
https://www.jianshu.com/p/5e7075f4875f#1. 浏览器缓存机制 - Android webView 缓存 Cache + HTML5 离线功能
https://juejin.im/entry/5709c96979bc44004c6cd5ca
让 WebView 支持文件下载
设置 DownloadListener,自定义下载
让 WebView 支持下载,需要给 WebView 设置下载监听器 setDownloadListener,DownloadListener 里面只有一个方法 onDownloadStart,每当有文件需要下载时,该方法就会被回调,下载的 URL 通过方法参数传递,我们可以在这里处理下载事件
1
2
3
4
5
6
7
mWebView.setDownloadListener(new DownloadListener() {
@Override
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
// TODO: 2017-5-6 处理下载事件
}
});
优势是我们可以感知下载进度,处理开始、取消、失败、完成等事件,不足之处是对下载的控制不如系统服务,必须自己处理网络带来的问题。
使用系统的下载服务 DownloaderManager
DownloadManager 是系统提供的用于处理下载的服务,使用者只需提供下载 URI 和存储路径,并进行简单的设置。DownloadManager 会在后台进行下载,并且在下载失败、网络切换以及系统重启后尝试重新下载。
系统在下载完成后会发送一条广播,里面有任务 ID,告诉调用者任务完成,通过 DownloadManager 获取到文件信息就可以进一步处理。
重写 WebViewClient 的 shouldOverrideUrlLoading() 拦截,通过外置浏览器打开
直接把下载任务抛给浏览器,剩下的就不用我们管了。缺点是无法感知下载完成,当然就没有后续的处理,比如下载 apk 完成后打开安装界面。
1
2
3
4
5
private void downloadByBrowser(String url) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse(url)); startActivity(intent);
}
WebView 记录上次阅读位置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 应用退出时,记录滚动的位置
@Override
protected void onPause() {
super.onPause();
int scrollY = webview_scrolling.getScrollY();
int scrollX = webview_scrolling.getScrollX();
LogUtil.i(TAG, "当前阅读位置:" + scrollX + "," + scrollY);
SPUtils.put(KEY_WEBVIEW_READ_POSITION_X, scrollX);
SPUtils.put(KEY_WEBVIEW_READ_POSITION_Y, scrollY);
}
// 加载url后,滚动到之前记录的位置
mScrolledX = (int) SPUtils.get(KEY_WEBVIEW_READ_POSITION_X, 0);
mScrolledY = (int) SPUtils.get(KEY_WEBVIEW_READ_POSITION_Y, 0);
if (mScrolledY >= 0 || mScrolledX >= 0) {
LogUtil.i(TAG, "滚动到上次已读位置:" + mScrolledY);
webview_scrolling.scrollTo(mScrolledX, mScrolledY);
mTvLastPosition.setText("上次阅读记录位置:" + "(" + mScrolledX + "," + mScrolledY + ")");
}
WebView 监听滚动
WebView 监听滚动,网页的滚动
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
public class ScrollingWebView extends WebView {
private static final String TAG = "webview";
private int mScaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
private OnScrollChangedCallback mOnScrollChangedCallback;
public ScrollingWebView(Context context) {
super(context, null);
}
public ScrollingWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ScrollingWebView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* onOverScrolled
*
* @param scrollX 第一个参数为距离远点的X轴的距离
* @param scrollY 第二个参数为距离远点的Y轴的距离
* @param clampedX 第三个参数当ScrollView滑动到左侧边界的时候值为true
* @param clampedY 第四个参数当ScrollView滑动到下边界的时候值为true
*/
@Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
LogUtil.d(TAG, "onOverScrolled,scrollX:" + scrollX + ",scrollY:" + scrollY + ",clampedX:" + clampedX + ",clampedY:" + clampedY);
}
/***
* onScrollChanged,
* @param scrollX 第一个参数为变化后的X轴位置
* @param scrollY 第二个参数为变化后的Y轴的位置
* @param oldScrollX 第三个参数为原先的X轴的位置
* @param oldScrollY 第四个参数为原先的Y轴的位置
*/
@Override
protected void onScrollChanged(final int scrollX, final int scrollY, final int oldScrollX, final int oldScrollY) {
super.onScrollChanged(scrollX, scrollY, oldScrollX, oldScrollY);
LogUtil.i(TAG, "onScrollChanged,scrollX:" + scrollX + ",scrollY:" + scrollY + ",oldScrollX:" + oldScrollX + ",oldScrollY:" + oldScrollY);
if (mOnScrollChangedCallback != null) {
mOnScrollChangedCallback.onScroll(scrollX - oldScrollX, scrollY - oldScrollY);
}
}
public OnScrollChangedCallback getOnScrollChangedCallback() {
return mOnScrollChangedCallback;
}
public void setOnScrollChangedCallback(@Nullable final OnScrollChangedCallback onScrollChangedCallback) {
mOnScrollChangedCallback = onScrollChangedCallback;
}
/**
* Impliment in the activity/fragment/view that you want to listen to the webview
*/
public interface OnScrollChangedCallback {
/**
* onScroll
*
* @param dx x方向变化的距离
* @param dy y方向变化的距离
*/
void onScroll(int dx, int dy);
}
}
WebView 监听滚动,监听 Webview 上的触摸
只有一页的网页,网页本身内容不能滚动,只是监听在 WebView 上的触摸滑动而已
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
public class TouchWebView extends WebView implements View.OnTouchListener, View.OnClickListener {
private static final String TAG = "webview";
private float mDownX;
private float mDownY;
private int mScaledTouchSlop;
private OnWebViewTouchListener mOnWebViewTouchListener;
public TouchWebView(Context context) {
this(context, null);
}
public TouchWebView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TouchWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
setOnTouchListener(this);
// setOnClickListener(this);
}
private void init() {
ViewConfiguration viewConfiguration = ViewConfiguration.get(getContext());
mScaledTouchSlop = viewConfiguration.getScaledTouchSlop();
}
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
mDownX = event.getX();
mDownY = event.getY();
logi("TouchWebView ACTION_DOWN:" + mDownX + "," + mDownY);
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
float upX = event.getX();
float upY = event.getY();
float dx = upX - mDownX;
float dy = upY - mDownY;
logi("TouchWebView ACTION_MOVE:" + dx + "," + dy);
if (mOnWebViewTouchListener != null) {
float distance = dy;
if (Math.abs(distance) >= mScaledTouchSlop) {
if (distance >= 0) {
mOnWebViewTouchListener.onScrolledDown(this, distance);
} else {
mOnWebViewTouchListener.onScrolledUp(this, distance);
}
} else {
mOnWebViewTouchListener.onWebViewNotScrolled(this, dx, dy);
}
}
break;
default:
break;
}
return false;
}
public TouchWebView setOnWebViewTouchListener(OnWebViewTouchListener listener) {
this.mOnWebViewTouchListener = listener;
return this;
}
@Override
public void onClick(View v) {
// if (mOnWebViewClickListener != null) {
// mOnWebViewClickListener.onClick(this);
// }
}
public interface OnWebViewTouchListener {
void onWebViewNotScrolled(TouchWebView webView, float dx, float dy);
void onScrolledUp(TouchWebView webView, float distance);
void onScrolledDown(TouchWebView webView, float distance);
}
private void logi(String msg) {
LogUtil.i(TAG, msg);
}
}
Android WebView 诊断与排查问题的方法和技巧
Android WebView 调试利器之 Chrome DevTools
必须从您的应用中启用 WebView 调试。要启用 WebView 调试,请在 WebView 类上调用静态方法 setWebContentsDebuggingEnabled。
1
2
3
4
5
6
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
在 DevTools 中打开 WebView
在 google 浏览器中输入以下地址:chrome://inspect
页面将显示您的设备上已启用调试的 WebView 列表
- Sources 区域
Sources 选项选择后在预览页的右边有一个 Sources 显示区域我这里需要调试的代码都写在 test.html 里面的,如果你是写在 js 里面的这个区域同样会显示您的 Js 文件点击打开后就显示内容区域了。
现在我们就可以调试了
- Console 区域
可以看到打印的 log 和当前变量的值和 Android 一样可以输入一个对象名就可以看到具体的值了如图我输入了一个 test 出来了对应的标签
- 内容区域
test.html 是我的内容区域
可能出现的问题
1.如果上面的调试代码也加了再输入 chrome://inspect 还是看不到列表(当然前提是应用要打开到 webview 页面)有可能第一次需要翻墙因为我的墙一直是开的这个是同事发现的。
2.这里我用的是 JsBridge 用的时候可能会出现点击没有反应
原因是 (应该是二者没同步导致的)JsBridge 和 Js 通讯写在 js 文件中的需要将代码库的 WebViewJavascriptBridge.js 文件放在当前项目的 assets 下面
开启 DiagnosableWebViewClient 日志输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* 诊断(错误信息)的WebViewClient,会以日志输出形式输出错误信息,便于发现网页的问题
*/
open class DiagnosableWebViewClient : WebViewClient() {
override fun onReceivedError(view: WebView?, errorCode: Int, description: String?, failingUrl: String?) {
super.onReceivedError(view, errorCode, description, failingUrl)
debugMessage("onReceivedError", "errorCode", errorCode, "description", description,
"failingUrl", failingUrl, "webview.info", view?.toSimpleString())
}
override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
super.onReceivedError(view, request, error)
debugMessage("onReceivedError", "request", request?.toSimpleString(), "error", error?.toSimpleString(),
"webview.info", view?.toSimpleString())
}
override fun onSafeBrowsingHit(view: WebView?, request: WebResourceRequest?, threatType: Int, callback: SafeBrowsingResponse?) {
super.onSafeBrowsingHit(view, request, threatType, callback)
debugMessage("onSafeBrowsingHit", "request", request?.toSimpleString(), "threatType", threatType,
"webview.info", view?.toSimpleString())
}
override fun onReceivedHttpError(view: WebView?, request: WebResourceRequest?, errorResponse: WebResourceResponse?) {
super.onReceivedHttpError(view, request, errorResponse)
debugMessage("onReceivedHttpError", "request", request, "errorResponse", errorResponse?.toSimpleString(),
"webview.info", view?.toSimpleString())
}
override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
super.onReceivedSslError(view, handler, error)
debugMessage("onReceivedSslError", "error", error, "webview.info", view?.toSimpleString())
}
}
Console 日志查看
1
2
3
4
5
6
7
8
9
10
11
12
open class DiagnosableChromeClient: WebChromeClient() {
override fun onConsoleMessage(message: String?, lineNumber: Int, sourceID: String?) {
//不需要调用super方法
debugMessage("onConsoleMessage", "message", message, "lineNumber", lineNumber, "sourceID", sourceID)
}
override fun onConsoleMessage(consoleMessage: ConsoleMessage?): Boolean {
debugMessage("onConsoleMessage", "message", consoleMessage?.toSimpleString())
//返回true,不再需要webview内部处理
return true
}
}
开启 WebView 远程调试
- 一定要限定运行设备大于等于 4.4 系统
- 强烈建议限定在 Debug 编译 (或等同条件) 包下开启,不建议 Release 包也启用该功能
- 配置完成后,启动 App,打开 Chrome,输入
chrome://inspect
1
2
3
4
5
fun WebView.enableRemoteDebugging() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && BuildConfig.DEBUG) {
WebView.setWebContentsDebuggingEnabled(true)
}
}
WebView 与 JS 的交互
见 WebView与JS.md