前阵子公司内部做了一个数据大屏,而后为了方便网点使用,让安卓端的同学开发了apk,可以让用户通过apk访问大屏。
然而apk并没有内置浏览器,而是直接打开设备自带的浏览器,而用户的设备又是各种各样,随之而来的就是兼容性问题。
这其中就遇到了一些用户打开apk后,白屏的现象
而我们内部的设备都可以正常使用,所以这个白屏问题必然是用户自带的浏览器版本太低导致的
我们也与组长交流过,就算这次大屏问题解决,后续也可能会有其他兼容性问题,所以不如让apk内置一个浏览器,后续也不会有相关问题,但是这个方案被作为备选方案,没办法只好硬着头皮上
首先既然白屏了就一定会有报错,解决这次白屏的过程中花费了太多的时间在查看报错上
vconsole
首先想到的是引入vconsole,想直接通过vconsole查看报错信息,奈何用户的设备上连vconsole都没有出现
而后偶然发现我们内部的手持设备打开apk也是白屏,不同之处在于手持设备打开有显示vconsole
而后就像找到救命稻草一般对着手持设备调试,然而即便手持设备有vconsole,vconsole中也没有log出错误信息或者其他有用的信息
此时就像无头苍蝇般对着代码进行注释,发布测试环境,查看现象,如此反复,花费了大量的时间,最后发现有些代码注释的情况下页面能够正常展示,不注释就白屏
这时候我就非常困惑,假如是代码兼容性问题为何vconsole中没有相关的错误信息
另外因为我用的是umi脚手架,本身就已经集成了兼容性相关的配置
,
也查看了打包之后的代码产物,故而我总认为代码兼容性上应该不会有问题
如下是vconsole的信息,了解umi的同学应该知道umi的app.tsx中暴露了一个patchRoutes函数,而我在该函数里log的信息这里都没有展示
所以我一度以为是umi自身的问题,但是翻遍了issue和各个论坛也没有解决
vconsole表现如下
查看错误信息
后来我用了另一种查看错误信息的方式,在document.ejs中引入一段捕获错误的代码,而后把错误信息放到页面上,如下
<!doctype html>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, target-densitydpi=device-dpi" />
<title>数字大屏</title>
</head>
<div id="user-agent"></div>
<div id="test-content">测试内容</div>
<div id="root" class="digit-front-app"></div>
</body>
<script>
function infoToBody(thing) {
const div = document.createElement('div')
div.innerText = thing
document.body.insertBefore(div, document.getElementById('test-content'))
var myLog = window.console.log
var myError = window.console.error
window.console.log = function(thing) {
myLog(thing)
infoToBody(thing)
window.console.error = function(thing) {
myError(thing)
infoToBody(thing)
</script>
<script>
var targetEle = document.getElementById("user-agent")
targetEle.innerText = window.navigator.userAgent
</script>
<script>
window.addEventListener("error", function(error) {
console.log('error', error);
var otherMsg = 'message: ' + error.message + '\n' + "filename: " + error.filename + '\n' + "lineno: " + error.lineno + '\n' + "colno: " + error.colno + '\n' + "error: " + error.error + '\n'
alert(otherMsg)
</script>
</html>
这里第一段代码是劫持了log和error,把log和error的信息展示到页面上
第二段是把设备信息展示在页面上
第三段是捕获错误,把错误信息展示在页面上
在此操作之后,使用手持设备访问大屏,终于发现了报错信息
cannot read property includes of undefined
这里还是想吐槽一下为毛这种信息vconsole没有打印出来呢
主要信息如上
而在我的代码中,用到includes的地方也不过三个
['09020102', '09020101'].includes(errorCode)
window.origin.includes('sit')
service?.includes('-dr')
把代码翻看出来后,才发现第二处的window.origin有问题,
查看相关资料后才发现两者是有区别的
window.origin
该属性是只读的。
origin的值是当前页面环境的源。
当源不是http和https协议,比如是file协议,则返回的值是null。
location.origin
表示的是当前页面的URL的源。
两者的兼容性也有区别
可以看到window.origin在chrome87以下的版本都不支持
而信息中显示用户的浏览器版本为chrome39
所以原本的写法也理所当然的报错了
到这里我就把window.origin 改为 window.location.origin
这时手持设备终于可以正常访问了
而后我就把修复后的代码发到测试环境让用户尝试一下
本来以为事情应该就这么告一段落了,
但是用户反馈依然是白屏。。。
这时候我就懵了。
因为此时又出现了那个问题,看不到错误信息。因为我们内部的设备都正常访问,又没法远程网点的大屏设备
一筹莫展之际,我发现caniuse网站上有个这么个东西
这个看起来像是可以模拟浏览器环境,于是乎我点进去(翻墙),发现了browserstack这么一款浏览器兼容性调试工具,
但是browserstack是收费的,免费的使用时间只有一分钟。。。 我还没来得及输入网址就给我弹没了
后来又查找了其他兼容性工具,有一些可以免费使用几天甚至半个月,但是环境太少了 chrome最低都有99,无法达到目的
而后在知乎上无意发现了这么个网站
每次会话可以使用3分钟,一天5次,虽然时间不长,但是也算勉强够了
之后用该工具打开网址,发现document.ejs中的部分代码报错了
function infoToBody(thing) {
const div = document.createElement('div')
div.innerText = thing
document.body.insertBefore(div, document.getElementById('test-content'))
var myLog = window.console.log
var myError = window.console.error
window.console.log = function(thing) {
myLog(thing)
infoToBody(thing)
window.console.error = function(thing) {
myError(thing)
infoToBody(thing)
说实话我现在也不太懂这个为啥报错,报的错误信息我也忘了,后来没看出个所以然,索性把上面那段代码中多余的部分删掉
function infoToBody(thing) {
const div = document.createElement('div')
div.innerText = thing
document.body.insertBefore(div, document.getElementById('test-content'))
window.console.log = function(thing) {
infoToBody(thing)
window.console.error = function(thing) {
infoToBody(thing)
如此就不报错了,当然这些代码只是测试环境上使用,生产本身就需要去掉
如此整个白屏问题基本结束
当然还需要注意umi的打包配置也需要调整,如下
targets: {
chrome: 37,
android: 5,
nodeModulesTransform: {
type: 'all',
最最重要的一点就是想尽一切办法查看报错信息,白屏一定有错误原因,没有拿到报错信息的话就无从下手,结果只能是各种盲猜,白白浪费时间