只想知道问题原因,直接看最后的总结就好了,以下是我对找这个bug的过程的梳理。
昨天收到一个bug任务:在Android5.0的手机上无法打开某H5页面。在加载后不久直接进入onPageFinished
方法后就没了下文。
- 观察到
WebView
打开其他页面没有问题,打开该页面时有个重定向,猜想到是重定向的问题。但是shouldOverrideUrlLoading
无论如何都进不了。 - 使用Postman测试url,拿到的是一个html文件:
<!DOCTYPE html> <html lang="zh-CN"> ... <script> ... location.href = locationUrl; </script> </html>
- 新建一个Demo,只放
WebView
,用二分法注释去掉所有无关的设置,运行WebView
复现bug。 - 死马当活马医了,几乎是实现了
WebViewClient
和WebChromeClient
的所有方法,然后调试,看它进入了哪些方法。总算是在WebChromeClient
的onConsoleMessage
方法中找到了一点蛛丝马迹:Uncaught SyntaxError: Unexpected identifier
,搜了一下一般是html中出现语法错误时的报错。 - 将第一个url下载的html文件放入Android的
assets
文件夹中,在本地loadUrl:
不出意外,仍然是在高版本手机上能顺利打开url,而在低版本手机上不行。@Override public void onClick(View v) { // 注意加上需要的参数 mWebView.loadUrl("file:///android_asset/test.html?..."); }
- 精简
test.html
,注释掉其他不必要代码,直接将locationUrl替换为目标url,奇迹出现了:在低版本手机上也能打开页面了。 - 二分法放开注释找到出现问题的代码块,功夫不负有心人,最后问题出在:
这个方法报错导致后面的var getQueryString = function(name) { let r, reg = new RegExp("(^|\\?|&|#)" + name + "=([^&#]*)(&|#|$)", "i"); ... };
location.href = locationUrl;
没再执行。以我对html半吊子的了解,let
关键字在低版本是不支持的,然后就尝试将let
改为var
,结果真的成功了!
总结
这个bug的原因是低版本Android上的WebView不支持js中的let关键字导致程序无法正常执行。因为h5文件中应用了高版本浏览器才支持的关键字let
导致程序中断没有执行到location.href = locationUrl;
。这种问题可以在WebChromeClient
的onConsoleMessage
方法中发现一些端倪。检测html时可以复制html到本地assets文件夹中,通过二分法注释代码查找原因。要注意的是标题所示的低版本不能进入shouldOverrideUrlLoading
方法的问题有可能并不是出在WebView
身上,比如本案例。