引言
某天,测试突然找到我,说线上医生端打开帖子详情页后,加载的进度圈一直不会消失。我的第一反应是一脸懵逼。what fuck???近两个版本这个页面我压根儿没有做任何改动。难道是用户使用的姿势不对???好吧,吐槽归吐槽,问题总归还是要解决的。
排查问题
问题复现的操作
和测试进一步沟通后,发现3.5.0版本从其他原生入口跳入到社区的帖子详情页正常。只有在8.0以上的手机从我们
App
内公用的H5
页面内跳入该页面才会出现该问题,而且一旦出现,再从其他所有的入口跳入也会出现该问题。探究问题产生的原因
借来测试的8.0手机,在自己本地调试后,发现8.0机型
webview
的onPageFinished
方法竟然没有回调?什么情况?立即去
google
搜索了下,翻了半天也没发现个所以然和解决办法。于是我就开始想,为什么前几个版本没有问题,用户版帖子详情页也没有问题。在最新的版本,公共H5
页面到底做了什么?看了下提交记录,发现最新的版本里同事为了解决公共H5
页在8.0以上手机首次加载白屏过长的问题,就对8.0以上的手机特意将公共H5
页从原先的remote进程放到了主进程中。话不多说,赶紧把这行代码注释掉,重新放到remote进程试试。几分钟后,运行查看效果确实解决了。
不过如果这样改,那岂不是解决一个问题又会产生原先的另外一个问题么?所以,该方案pass掉。
那还有别的办法么?想了想,如果
onPageFinished
方法无法回调,是不是说可以将原先这部分的操作转移到WebChromeClient
中的onProgressChanged
方法中呢。毕竟这个方法本来就比onPageFinished
方法要靠谱的多。1
2
3
4
5
6
7
8
9
10
11
12
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
if (newProgress > 85){
//开始注入js文件
//
}
if (newProgress == 100){
//隐藏进度条
//原先结束的操作
}
}运行代码后,发现该方法是会回调的,同时进度条的问题解决了。但是…原先我们在页面加载结束后,会通过
JsBridge
调用H5
的方法,在这里竟然调用后竟然不起作用了。通过调试发现Js
文件确实已经注入成功了,但是在调用H5
的方法时,在H5
的方法池中找不到已注册的方法!这下彻底懵逼了,该怎么搞呢?
到第二天,同事辅助排查的时候,发现在公共
H5
页面有如下代码。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public void onResume() {
if (webView != null) {
//激活WebView为活跃状态,能正常执行网页的响应
webView.onResume();
//激活WebView为活跃状态,能正常执行网页的响应
webView.resumeTimers();
}
}
public void onPause() {
BridgeWebView webView = this.mHolder.getWebView();
if (webView != null) {
//当页面被失去焦点被切换到后台不可见状态,需要执行onPause
//通过onPause动作通知内核暂停所有的动作,比如DOM的解析、plugin的执行、JavaScript执行
webView.onPause();
//当应用程序(存在webview)被切换到后台时,这个方法不仅仅针对当前的webview而是全局的全应用程序的webview
//它会暂停所有webview的layout,parsing,javascripttimer。降低CPU功耗。
webView.pauseTimers();
}
}这两段代码是之前为了解决页面处于后台视频还会继续播放的问题。看
webView.pauseTimers()
方法,在页面失去焦点的时候调用它,会将针对全局Webview
。那么问题基本就明了了,从公共
H5
跳到帖子详情页,触发了该方法,而在医生版的帖子详情页中的onResume
方法中并没有调用webView.resumeTimers()
,所以此时webview
仍处于pauseTimers
设置的后台状态,最终导致onPageFinished
方法未回调出现问题。
解决方案
暂时先在医生版帖子详情页中的onResume
方法中添加webView.resumeTimers()
,后期准备将两端帖子详情页统一放到web模块,公用一个配置。
结论
经过上面的测试分析,发现在8.0以上的手机如果两个内嵌Webview
的原生页面,前一个H5
页面调用了webView
的pauseTimers()
方法,而后面的页面没有调用resumeTimers
来恢复的话,会导致WebViewClient
方法的onPageFinished
不会回调。