2***@qq.com
2***@qq.com
  • 发布:2026-09-21 15:37
  • 更新:2026-09-21 15:37
  • 阅读:17

【Android】App 切后台恢复后,navigateTo 预创建页面出现 VISIBLE+0x0 幽灵 WebView 窗口,页面栈正常但画面空白、点击穿透下层页面

分类:uni-app

问题简述

uni-app Android 平台,App 按 Home 键退后台,再切回前台后,后续通过 uni.navigateTo 打开的新页面会出现幽灵页面:页面生命周期正常执行、页面栈入栈成功、plus.webview.isVisible() 返回 true,但页面无画面渲染,触摸事件穿透到底层上一页,点击操作作用于下层页面。
根因定位:uni Android 每个页面为独立原生子窗口(AbsoluteLayout → WebParentView → WebView)。为加速跳转 runtime 会预创建 INVISIBLE+0x0 空窗口;真正打开页面时,需要设置 VISIBLE + 设置全屏尺寸。App 后台恢复 (onResume) 场景下,预创建的页面窗口仅标记为 VISIBLE,遗漏设置 LayoutParams 全屏宽高,生成VISIBLE + 0×0的原生容器。
额外诱因:App onShow 阶段频繁非幂等修改 Window Flag / 导航栏颜色,会触发 Activity 全局 requestLayout,会显著提高该 bug 复现概率;将系统栏修改逻辑改为幂等(仅值变更才修改),可降低复现概率,但无法彻底根除。

复现环境

  • 平台:Android(测试机型:xxx,Android 版本:xxx)
  • uni-app 版本:xxx
  • 打包方式:App 离线打包 / 云端打包(runtime 版本:xxx)
  • 项目类型:uni-app(非 x)

复现步骤

  1. 打开 App,正常进入首页 / 我的页面;
  2. 点击 Home 键,App 退至后台,停留数秒;
  3. 从系统任务栏切回 App(触发 onResume);
  4. 执行 uni.navigateTo 跳转新页面:
    • 第一次跳转:使用后台恢复之前已经预创建好的窗口,页面正常展示;
    • 第二次及之后跳转:使用后台恢复后新预创建的原生窗口,触发幽灵页问题。

现象表现

  1. JS 层:onLoad / onShow 正常触发,页面栈正常入栈,接口请求正常执行;plus.webview.getWebviewById 获取 webview 对象,isVisible() 返回 true;
  2. 原生视图树(hierarchyviewer/LayoutInspector 抓取对比)
    ✅ 正常页面:
AbsoluteLayout VISIBLE 1440x3200  
└─ WebParentView 1440x3200  
   └─ WebView内核 1440x3200

❌ 幽灵异常页面:

AbsoluteLayout VISIBLE 0x0  
└─ WebParentView 0x0  
   └─ WebView内核 0x0
  1. 视觉:屏幕仍然显示下层旧页面,新页面无任何渲染画面;
  2. 交互:点击事件穿透 0 尺寸视图,全部命中下层页面,无法操作新页面;
  3. 无效尝试:调用 webview.show ()、render:"always"、主动 requestLayout 均无法修复;仅等待下一次 App 前后台切换 onResume 时 runtime 会重新统一计算窗口尺寸,幽灵页面才会恢复正常。

根因分析

uni-app Android 运行时页面机制:每个页面是挂载在根容器下独立 WindowManager 子 View。navigateTo 为优化打开速度,提前预创建页面容器,初始状态 INVISIBLE + 0x0(此为正常预加载逻辑)。
页面正式打开,runtime 需要执行两步:

  1. 将 AbsoluteLayout 可见性设置为 VISIBLE
  2. 给原生 View 设置全屏宽高 LayoutParams

Bug 触发逻辑:App 后台恢复 onResume 流程中,runtime 新建预加载页面,在触发 navigateTo 时,只执行了可见性修改,遗漏设置全屏尺寸,形成 VISIBLE、宽高为 0 的原生容器。

0 尺寸 VISIBLE 视图特性:

  • 可见性标记为 VISIBLE,JS API 读取可见性为 true;
  • 原生 View 宽高 0,不会绘制像素,不会接收触摸事件,事件穿透下层。

诱发条件补充
在 App onShow 生命周期内,反复调用 addFlags/clearFlags/setNavigationBarColor 修改窗口属性,会触发 Activity 全局 requestLayout。在 onResume 敏感时机,全局重布局会干扰 runtime 内部页面窗口尺寸恢复逻辑,提高 bug 出现概率;将系统栏相关修改改为幂等执行(仅参数发生变化时才修改 Window 属性),可降低复现概率,但不能完全杜绝该底层缺陷。

临时兜底方案(JS + plus.android 反射修复)

仅作为上层兜底补丁,非根治方案,期待 runtime 原生修复

  1. 视图检测工具:通过plus.android反射遍历页面视图树,识别 VISIBLE && (width==0 || height==0) 的页面容器;过滤 INVISIBLE 的正常预加载窗口;
  2. 自动修复:检测栈顶 webview 为 0 尺寸幽灵页时,手动调用webview.setStyle强制赋值全屏宽高(top:0,left:0, 屏幕宽高),补齐 runtime 缺失的布局参数;
  3. 时序:页面 onShow/onReady 延时 500ms 执行检测;navigateTo 入栈 300ms 执行检测;
  4. 优化系统栏代码:syncSystemBarColors 改为幂等,Window Flags、导航栏颜色、setSystemUiVisibility 仅在值变更时调用,避免 onShow 反复触发全局窗口重布局。

期望

  1. 修复 Android runtime,App 后台恢复 onResume 场景下,预创建页面打开时,保证同时设置 VISIBLE 和全屏 LayoutParams,杜绝 VISIBLE+0x0 幽灵 WebView 容器;
  2. 优化 onResume 阶段多页面窗口尺寸计算逻辑,避免全局窗口布局干扰子页面尺寸初始化;
  3. 文档 / 更新日志补充该场景修复说明。
0 关注 分享

要回复文章请先登录注册