记录 Android WebView内核更新,安全区 和 Insets 消费问题

大概2026刚过完年,线上 H5 页面中原本正常的弹窗,突然在底部多出了几十像素的透明空白。

第一反应是 Android 侧 Insets 的适配问题------但 Android 的 WebView 应该没有 iOS 那样原生支持 env(safe-area-inset-bottom) CSS 变量,按理说不应该有这个问题。

带着这个疑问开始排查。

排查过程

项目里使用的是 van-action-sheet 组件,通过 chrome://inspect 调试页面,在 DevTools 中检查样式,发现 padding-bottom: env(safe-area-inset-bottom); 是生效的, padding-bottom 的值不是 0

这说明 Android WebView 已经将 Window Insets 信息注入到了 CSS 环境变量中。

翻阅 Android 官方文档后找到了答案:

了解窗口边衬区 | Android Developers

Android WebView 内核在 144 版本中会将系统窗口的 Inset CSS 环境变量的形式透传给 WebView 内的页面。一旦 Native 层没有正确"消费"这些 Insets,WebView 就会感知到它们,并反映到 safe-area-inset-* 变量上。

问题根因

常见的 Insets 处理写法如下:

kotlin 复制代码
ViewCompat.setOnApplyWindowInsetsListener(findViewById(android.R.id.content)) { v, insets ->
    val barInsets = insets.getInsets(WindowInsetsCompat.Type.navigationBars())
    v.updatePadding(bottom = barInsets.bottom)
    insets // 直接返回原始 insets,未消费
}

这段代码虽然给 View 加上了底部 padding,但 将原始 insets 原封不动地返回,意味着这些 Insets 没有被消费(consume)。子 View(包括 WebView)仍然可以感知到完整的 Insets 值,进而影响 CSS 环境变量。

解决方案

参考官方文档:Avoid ghost padding by zeroing insets

在处理完 Insets 后,构建一个新的 WindowInsetsCompat,将已处理的 Insets 类型置为 NONE,从而告知系统这部分 Insets 已被当前层级消费:

kotlin 复制代码
ViewCompat.setOnApplyWindowInsetsListener(findViewById(android.R.id.content)) { v, insets ->
    val types = WindowInsetsCompat.Type.navigationBars() or WindowInsetsCompat.Type.ime()
    val barInsets = insets.getInsets(types)
    v.updatePadding(bottom = barInsets.bottom)

    // 消费 navigationBars 和 ime,避免 WebView 感知到这些 Insets
    WindowInsetsCompat.Builder(insets)
        .setInsets(types, Insets.NONE)
        .build()
}

改动后,WebView 内 safe-area-inset-bottom 恢复为 0,弹窗底部的透明空白消失。

总结

对比项 修复前 修复后
Insets 返回值 原始 insets(未消费) 构建新的 WindowInsetsCompat(已消费)
WebView CSS 变量 safe-area-inset-bottom 非零 safe-area-inset-bottom 为 0
页面表现 弹窗底部出现多余透明空白 正常显示

结论: 在 Android 中,如果 Native 层自己处理了导航栏/IME 的 Insets,必须在监听器中返回消费后的 WindowInsetsCompat,否则 WebView 会继承这些 Insets 并将其映射到 CSS 的 safe-area-inset-* 环境变量,导致 H5 页面布局异常。

相关推荐
_祝你今天愉快7 小时前
从驱动来分析服务的添加过程
android
Dovis(誓平步青云)9 小时前
折叠屏悬停看视频,上半屏和下半屏应该各做什么
android·java·服务器·开发语言·安全·音视频
alexhilton10 小时前
让架构边界变成可执行的测试
android·kotlin·android jetpack
hai_android12 小时前
SendChannel 与 ReceiveChannel 通信机制
android
数据治理自习室14 小时前
AI 应用评测体系(GraphRAG)
android·大数据·人工智能·kotlin
爱笑鱼14 小时前
Android 系统启动机制(五):system_server 是 init 启动的,还是 Zygote fork 出来的?
android
智购科技无人售货机工厂15 小时前
2026自动售货机防拆机物理安全设计:从安全螺丝到结构互锁的工程实践~YH
android·网络·驱动开发·python·单片机·安全·云原生
开开心心就好15 小时前
电子教鞭工具支持画框写字插图片功能齐全
android·开发语言·前端·javascript·人工智能·pdf·html
Dovis(誓平步青云)15 小时前
拍视频前先把镜头想清楚:做一个分镜取景辅助器
android·java·服务器·javascript·人工智能
峥嵘life17 小时前
Android16 系统 APEX 模块说明
android·大数据·开发语言