WebView JS 桥只注入主 frame,iframe 内拿不到 (WebView JS Bridge Top-Frame Only)
症状
同一套导航页面,两种访问方式结果完全不同:
| 访问方式 | 页面结构 | 学校桥 window.android |
|---|---|---|
navi.6767.chat/ | React SPA,导航页被 <iframe src="navi/index.html"> 嵌入 iframe | ❌ iframe 里 window.android 不存在 |
navi.6767.chat/navi | navi/index.html 就是主 frame | ✅ 直接可用,定位秒成 |
用户一直从 SPA 主入口进(/),导航页在 iframe 里拿不到桥、走 postMessage 代理链路又失败,一直以为「学校桥拿不到」;偶然直接访问 /navi,导航页变主 frame,桥直接可用,定位成功。
触发条件
- 第三方 Android 壳(
addJavascriptInterface注入window.android)内嵌本 Web 应用; - 本应用是 SPA + iframe 架构:功能页(导航)嵌在主壳页面的
<iframe>里; - 功能页依赖 WebView 注入的 JS 桥。
根因
Android WebView 的 addJavascriptInterface 只把 JS 对象注入主 frame(WebView 加载的顶层文档)。 iframe 子文档拥有独立的 JS 全局作用域,拿不到注入到主 frame 的 window.android。这是 WebView 的固有限制,不是页面代码问题。
因此同一个 URL 的 navi/index.html:
- 被 iframe 嵌入时 → 子 frame,
window.android === undefined; - 直接访问时 → 主 frame,
window.android存在且可调。
要让 iframe 内页面用上桥,只能主 frame 代调后 postMessage 回传(本项目 App.jsx 的 navi-request-school-bridge 代理),而代理链路多一跳、依赖主 frame React 壳版本(还叠加了 CDN 缓存旧壳的风险),远不如让功能页直接做主 frame 稳。
解决
让依赖 JS 桥的功能页直接做主 frame,不要嵌 iframe。 本项目的 navi.6767.chat/navi 就是直接访问,桥可用。SPA 主入口里用 iframe 嵌入导航页属于过度嵌套,对 WebView 桥接场景是自找麻烦。
如果必须 iframe 嵌入,只能走「主 frame 代调 + postMessage 回传」代理,并保证:
- 主 frame 壳是最新版(含代理分支)——注意 CDN/WebView 缓存可能给旧壳;
- 代理有超时与兜底(本项目
app.js的 2.5s watchdog 回落直接调宿主 frame 桥)。
下次怎么识别
- 「手机上 APP 里不行 / 浏览器里行」先问一句:页面是主 frame 还是 iframe?
- 功能页依赖的 native 桥在 iframe 里测不到 → 先查是否被
<iframe>嵌入,再查是不是直接访问该 URL 就能用; - 诊断:直接访问功能页 URL(绕开 SPA)测桥,能通则问题锁定在 iframe 嵌套层。
相关概念
- addJavascriptInterface
- iframe / 多 frame 架构
- postMessage(跨 frame 通信)
- 见同目录 WebView 桥把 native 物理像素当 CSS px(Android 壳顶部留空位)
本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/Programming