背景
混合应用,App 嵌套 H5,H5 技术栈:vue 2.6。 项目本身不是从零开发的。
问题
原生 app 访问 H5 功能页面XXX,在 vivo x21 i 机型上页面空白。
探究过程
一、初诊断
因为没有这个机型,所以通过 wetest 的云真机测试,结果能够复现。
面对这个问题,首先想到的是看看控制台有没有报错,开发环境包打开 vconsole。结果是 console 没有任何报错。
接口也没有异常。
二、看代码
那么到底有什么特殊情况呢?还是先看看代码。
发现原生先是到 A 页面,然后跳转到 B 页面。会不会是在跳转的过程中发生了什么?
再仔细观察效果,打开 A 页面似乎能看到页面已经渲染元素,然后页面空白。
三、手机浏览器中
本地测试当然没有问题,访问 A 页面正常跳转 B 页面。
对应的机型上,看浏览器能否打开 A 页面?看能否正常跳转 B 页面?一开始发现浏览器也不能正常打开,因为地址有传参,而且在 app 中有 token,这些在浏览器中都没有,所以并不能把直接在浏览器中打开页面和在 app 中打开同等看待。浏览器中页面空白是因为接口报错。
好在 H5 逻辑已经有处理请求的 header 参数(同时在 localstorage 中获取),所以只浏览器的本地存储中设置 token;而路径地址上的传参没有问题,在路径上添加参数就可以。
在云真机上做所有这些操作简直考验人的耐心,所以一度还写错一个本地存储字段。周折一些时间。
最终,证明浏览器中访问 A 页面正常,跳转 B 页面也正常。
四、怎么调试
同事认为空白可能是 ES6 兼容的问题。搜了一下,可以尝试处理试试。那问题来了,怎么调试呢?平时改 bug 无非是本地启动修改,浏览器中看效果。现在我们要在特定的机型上、从 app 中打开页面查看效果,而且只能通过云真机测试。
我想,如果有真机,可以通过将开发环境映射为本地环境,这样就可以修改本地代码来调试。
通过云真机,我们只能每次改动,每次让安卓开发给我打个包,再上传 app,这样简直不敢想……
后来明白,安卓的包并不需要改,我们只需要改前端项目即可,不过需要发布到开发环境,这样才能生效。虽然还是比较麻烦,不过也不是不可行,至少不需要麻烦别人了。
然后要尽可能的尝试可能的原因,不能盲目的试错。
五、vue cli3 安卓低版本 兼容问题 babel-polyfill
根据以上关键词搜索了一些文章,大致都差不多。做了以下处理:
新增 .babelrc:
{
"presets": ["@babel/preset-env"],
"plugins": [
"@babel/plugin-transform-runtime"
]
}
修改 babel.config.js:
module.exports = {
presets: [
'@vue/app'
[
'@vue/app',
{
'useBuiltIns': 'entry',
polyfills: [
'es6.promise',
'es6.symbol',
'es6.array.iterator',
'es6.object.assign',
'es6.let'
]
}
]
],
plugins: [
...
]
修改 vue.config.js:
transpileDependencies: ['node_modules/webpack-dev-server/client'],
chainWebpack: config => {
config.entry.app = ['babel-polyfill', './src/main.js'];
修改 main.js:
import 'babel-polyfill'
import Es6Promise from 'es6-promise'
Es6Promise.polyfill()
安装依赖:
npm install --save-dev @babel/core @babel/plugin-transform-runtime @babel/preset-env es6-promise @babel/polyfill
最终无法修复。
六、vue router replace 页面空白
这个 github.com/vuejs/vue-r… 中反馈了router replace 的问题,然后尝试用 push 替换 replace,发现也没有解决问题。
然后又去了解了下 router 的实现原理。
尝试直接 location.replace(B),依然不行。
尝试 location = B,不行。
七、不通过A,直接访问 B 页面
在我们目前的业务中,可以不通过 A,直接访问 B,于是让安卓开发帮忙打个包,直接访问 B,然后在云真机上测试,仍然有问题。
这么做,进一步确定为就是B的问题,跟跳转无关。虽然一开始说 A 页面渲染,就可以排除这一点了。
八、测试 B 页面
既然就是 B 页面的问题,感觉离解决问题越来越近了。我们把 B 页面简化到:
<template>
<pages id="page">
<div class="list-tips">测试</div>
</pages>
</template>
发现页面仍然是空白,似乎连 app 的页面 title 也没有了。
九、vue-router 路由
看似很接近了,突然又没了思路。
<pages>
是什么组件?跟这个有关吗?- 上面说的 title 在 js 中赋值,说明页面 js 正常执行了
再一次确认 app 打开其他页面正常,那么如果这里不是打开 B 页面而是其他页面呢?如果 B 页面路由到其他页面呢?
检查 B 页面的路由文件:
export default [
{
path: '/prescribe',
name: 'prescribe',
component: Prescribe,
redirect: '/prescribe/prescriptions',
children: [
{
path: 'prescriptions',
name: 'prescriptions',
component: PrescriptionList
},
跟 redirect 有关吗?没有关系,这里是父路由的重定向。
那么跟能够正常打开的页面的路由对比一下?没有使用 nested routes,没有 children。
测试一下:
{
path: '/prescribe/prescriptions',
name: 'prescriptions',
component: PrescriptionList,
}
哦吼!正常打开!
十、解决
那么这到底是什么原因呢?vue-router 嵌套路由在安卓低版本的 webview 中导致页面空白,搜了一下,没有相关的文章,似乎库也没有相关的 issue,这很正常,因为在浏览器中都是正常的。那么低版本的安卓的 webview 到底有什么特殊?这一点我暂时也不知道怎么探索验证。
解决当然就只能不用嵌套路由咯。
网上很多关于嵌套路由页面空白的问题,要么是子路由多写了/
,要么是其他问题。
总结
如果回过头来看,似乎早就应该意识到问题所在,但问题是当你困在问题当中时,就很难理清思路。而且对整个项目不了解,就会怀疑是某些环节出了问题。最后是云真机真的很难用。
最后真的想吐槽 Vue,这是什么坑爹设计,页面空白,不报错,真让人吐血…… 没有经验的人真的要浪费时间,以前经典的白屏问题,控制台至少也报错。
参考
- react/vue在某些低版本安卓手机浏览器白屏解决办法:www.love85g.com/?p=1816
- vue中使用babel-polyfill解决低版本浏览器不兼容问题:www.cnblogs.com/chenguiya/p…
- replace在部分android机型下无效:github.com/vuejs/vue-r…
- router.replace doesn't work as expected in some android webiews:github.com/vuejs/vue/i…
- Nested Routes:v3.router.vuejs.org/guide/essen…
- vue配置嵌套路由,页面一直空白:juejin.cn/post/684490…