14-AI智能管家JSBridge深度问答

AI 智能管家 JSBridge 深度问答(面试 + 实战)

用途:把 JSBridge 双向通信机制讲透,含 6 个深度问题 + 完整开门案例

适合:被追问「getToken 是步骤几」「method 命名规则」「原生→H5 怎么回传数据」时脱口而出

核心思想:method 名字串起 H5→RN→H5 三步,requestId 串起一次会话


一、JSBridge 双向通信机制(10 步)

先记住这张图,后面所有问题都围绕它展开。

步骤速查表

步骤 谁 调什么 代码位置
step1 H5 window.ReactNativeWebView.postMessage H5 端 SDK
step2 WebView onMessage 回调 自动触发 WebView.js prop
step3 webViewHandlers.js handleWebViewMessage 函数 utils/webViewHandlers.js
step4 webViewHandlers.js handlers[method] 按 method 查表 同上
step5 原生 handler 调业务 API(fetch) utils/agentToolHandlers/doorHandlers.js
step6 业务后端 返回数据 ---
step7 原生 handler ctx.sendMessage(method, data, requestId) doorHandlers.js
step8 webViewHandlers.js 到 WebView.js ctx.sendMessage 到 webViewRef.injectJavaScript WebView.js
step9 H5 window.dispatchEvent nativeMessage 注入的 JS 触发 H5 监听
step10 H5 拿到数据 渲染聊天界面 H5 端 SDK

二、6 个深度问题速答

Q1:智能体云服务(nexa.newbest.com.cn)是哪个厂商?

A :公司域名 newbest.com.cn 的子域名,大概率是采购的第三方 SaaS (思必驰/涂鸦/大厂之一)。LLM 包含在云服务里,前端不需要单独买。

判断依据:

证据 推断
域名 <YOUR_AGENT_DOMAIN> 公司自有域名,不是第三方云厂商
tenantId + agentId 多租户配置 SaaS 服务典型特征
SDK AgentChatSDK 第三方厂商提供的标准 SaaS SDK 命名

LLM 处理 :智能体云服务内部封装,前端零感知。买的套餐里包含 LLM 调用次数。


Q2:前端需要理解这么详细吗?RN 项目能区分「智能体云服务」和「LLM」吗?

A :前端不用理解这么深 。RN 代码完全看不见 LLM ,把云服务当黑盒。

前端只需要理解 3 句话:

markdown 复制代码
1. RN 端把用户说的话发给智能体云服务
2. 等结果
3. 把结果显示出来

中间的「云服务怎么调 LLM、怎么过滤权限 」完全在云服务内部,前端零感知。

层级 RN 项目能看到 看不到
智能体云服务 能看到(URL <YOUR_AGENT_DOMAIN>) ---
LLM 完全看不到 模型名称 调用次数 prompt
工具注册表 完全看不到 哪些工具注册了
权限过滤 完全看不到 用户能用哪些工具

Q3:智能体云服务怎么处理工具权限?

A :大致流程是用户身份 → 权限过滤 → 工具列表 + 用户消息 → LLM → 二次校验 → 返回。前端不可见。

推测的流程:

markdown 复制代码
用户发请求「帮我开一号楼大门」
   智能体云服务 收到请求
   1. 识别用户身份 拿到 userId/token
   2. 查该用户的权限(A 能调哪些工具)
   3. 过滤工具注册表(A 只能用 [查天气, 开门])
   4. 把用户身份 + 过滤后的工具列表 + 用户消息 一起发给 LLM
   5. LLM 返回 要调开门
   6. 智能体云服务再次校验权限(防止 LLM 幻觉)
   7. 返回结果给前端

关键 :LLM 不可信 ,可能幻觉瞎说或被 prompt 注入越权,云服务永远要做最终权限校验。


Q4:onMessage / injectedJavaScript / injectJavaScript() 是啥?

答:3 个相似但完全不同的东西
名称 类型 何时调用 用途
injectedJavaScript WebView 的 prop 初始化时 跑一次 注入静态配置 BASE_URL 禁用缩放
injectJavaScript() WebView 实例的 方法 任何时候手动调用 动态注入 JS 业务数据回传
onMessage WebView 的 prop 回调 H5 发消息时触发 接收 H5 发来的数据

对照代码:

javascript 复制代码
// WebView.js 第 421 440 行
<WebView
  onMessage={this.handleWebViewMessage}              // Q4-A 监听 H5 发来的消息
  injectedJavaScript={injectedJavaScript}            // Q4-B 初始化时跑一次
  injectedJavaScriptBeforeContentLoaded={...}        // Q4-C DOM 加载前注入
/>
javascript 复制代码
// WebView.js sendMessageToWebView 方法
sendMessageToWebView = (method, data, requestId) => {
  const jsCode = `
    window.dispatchEvent(new CustomEvent('nativeMessage', {
      detail: { method: '${method}', requestId: '${requestId}', data: ${JSON.stringify(data)} }
    }));
    true;
  `;
  // 这里调用的是 webViewRef 的实例方法 不是 prop
  this.webViewRef.current?.injectJavaScript(jsCode);
};

对照表:

业务数据回调用哪个 用 prop 还是方法
初始化静态配置 injectedJavaScript prop
业务数据回传 webViewRef.current.injectJavaScript() 方法
三个 prop / 方法分别注入什么?
名称 注入时机 注入内容
injectedJavaScriptBeforeContentLoaded DOM 加载前 宿主 App 信息 安全区域 console 转发
injectedJavaScript DOM 加载后 BASE_URL isInXingzhijia 标记 viewport
onLoad 回调里 injectJavaScript() 加载完成后 最新的 __SAFE_AREA_INSETS__
sendMessageToWebView() 里的 injectJavaScript() 任何时候 业务数据回传(dispatchEvent nativeMessage)

业务 API 数据回传走的是 sendMessageToWebView 里的 injectJavaScript(),不是 injectedJavaScript prop。


Q5:onShouldStartLoadWithRequest 是 WebView 自带的吗?

A :是 react-native-webview 提供的 prop,业务自定义 URL 拦截逻辑。

项目代码:

javascript 复制代码
handleShouldStartLoadWithRequest = (request) => {
  const currentUri = this.props.route?.params?.uri;
  const requestUrl = request?.url;

  // 规则 1: 空 URL 放行
  if (!requestUrl) return true;

  // 规则 2: 非顶层 frame 放行
  if (request?.isTopFrame === false) return true;

  // 规则 3: 不是 xingzhijia-agent 场景放行
  if (!currentUri.includes('xingzhijia-agent')) return true;

  // 规则 4: javascript: 或 about:blank 放行
  if (requestUrl === 'about:blank' || requestUrl.startsWith('javascript:')) return true;

  // 规则 5: 相对路径放行
  if (!requestUrl.startsWith('//') && !/^[a-z][a-z0-9+.-]*:/i.test(requestUrl)) return true;

  // 规则 6: 相同 URL 放行
  if (currentUri.split('#')[0] === requestUrl.split('#')[0]) return true;

  // 规则 7: 外部链接 用 Linking.openURL 在外部浏览器打开
  Linking.openURL(requestUrl).catch(console.warn);
  return false;  // 阻止 WebView 内导航
};

用途 :安全防护 ,防止用户在 H5 里点恶意链接导致 WebView 跳到钓鱼网站。拦截后用外部浏览器打开,用户能看到地址栏。

⚠️ 项目里这个 prop 目前被注释了 (前面有 //),目前没有启用。


Q6:流程图对不对?injectedJavaScript 是不是传业务 API 数据?

A :你的发现完全正确!

injectedJavaScript 这个 prop ≠ 业务 API 数据回调。

业务 API 数据回调用的是:

  1. sendMessageToWebView(method, data, requestId)(自定义函数)
  2. 内部调用 webViewRef.current.injectJavaScript(jsCode)(实例方法)
  3. 注入的 JS 里 window.dispatchEvent('nativeMessage', {detail})
  4. H5 监听 nativeMessage 事件拿到数据

injectedJavaScript prop 注入的是 :BASE_URL isInXingzhijia 标记 viewport 禁用缩放(静态配置)。

修正文档时的核心澄清:

步骤 用什么 文档之前描述 修正后
step8 原生→H5 注入 JS injectJavaScript(歧义) webViewRef.current.injectJavaScript() 实例方法
初始化 静态配置 injectedJavaScript prop 明确为 prop 加实例方法

三、method 命名规则 + 完整开门案例

你提的核心问题

H5 给 RN 通信定义的方法是咋样的?RN 返回消息给 H5 又是怎样的方法命名?getToken / getUserInfo 是步骤 step4 的方法,还是步骤 step7 的 sendMessage 方法?

核心答案:method 名 = handler 名 = sendMessage 参数,三者必须一致

getToken 既是:

  • 步骤 step4 的 handler 名(handlers['getToken'])
  • 步骤 step7 的 sendMessage 第一参数(sendMessage('getToken', ...))
  • 步骤 step9 的 H5 响应 method 字段({method: 'getToken', ...})

三者必须同名,因为:

  • 步骤 step4:handlers['getToken'] 表示「H5 想调 getToken 这个能力」
  • 步骤 step7:sendMessage('getToken', ...) 表示「回传的数据 method 是 getToken」
  • 步骤 step9:H5 用 method 名字区分是哪个请求的响应

method 命名规范

类型 命名规则 例子
拉数据 查 getXxx getToken / getUserInfo / getAgentContext / getServicePhone
查列表 queryXxx / getUserXxx queryBuildings / getUserAllDoor
执行动作 verbXxx doorOpen / verifyDoorHealth / callPhone
跳转 goXxx goBack

H5 发起:

javascript 复制代码
{
  method: '方法名',       // 驼峰命名
  params: {...},         // 参数对象
  requestId: '唯一ID'    // 关联响应
}

RN 响应:

javascript 复制代码
ctx.sendMessage('方法名', result, requestId);
//                  ↑ 同一个方法名

四、完整案例:「帮我开一号楼大门」(3 轮 H5↔RN 通信)

这是 AI 智能管家最经典的场景,包含 3 个 handler 调用 + 4 次 H5↔RN 通信。

全流程时序图

关键代码对照

step1 H5 发请求(H5 端 SDK 调用)
javascript 复制代码
// 第一轮 拿楼宇
window.ReactNativeWebView.postMessage(JSON.stringify({
  method: 'getBuildingInfo',
  params: {},
  requestId: 'req-001'
}));

// 第二轮 拿门禁列表
window.ReactNativeWebView.postMessage(JSON.stringify({
  method: 'getUserAllDoor',
  params: {buildingId: 1, employeeNo: 'xxx'},
  requestId: 'req-002'
}));

// 第三轮 开门
window.ReactNativeWebView.postMessage(JSON.stringify({
  method: 'doorOpen',
  params: {
    deviceSerial: 'abc',
    buildingId: 1,
    employeeNo: 'xxx'
  },
  requestId: 'req-003'
}));
step4 + step7 原生 handler 实现(RN 项目代码)
javascript 复制代码
// src/utils/agentToolHandlers/doorHandlers.js

// handler 名 = method 名 = sendMessage 名(必须一致)
export async function getBuildingInfoHandler(params, requestId, context) {
  const {sendMessage} = context;
  // 从 redux 拿 不调 API
  const buildingId = context.building?.curId;
  sendMessage('getBuildingInfo', {buildingId}, requestId);
  //                ↑ 步骤 step7 调用 sendMessage
}

export async function getUserAllDoorHandler(params, requestId, context) {
  const {sendMessage} = context;
  const {buildingId, employeeNo} = params;
  // 调业务 API
  const result = await getUserAllDoorNew(buildingId, employeeNo);
  sendMessage('getUserAllDoor', result, requestId);
  //                ↑ 步骤 step7
}

export async function doorOpenHandler(params, requestId, context) {
  const {sendMessage} = context;
  const {deviceSerial, buildingId, employeeNo} = params;
  // 调开门 API
  const result = await doorOpen({deviceSerial, buildingId, employeeNo});
  sendMessage('doorOpen', result, requestId);
  //                ↑ 步骤 step7
}
step9 H5 接收响应(H5 端 SDK 内部)
javascript 复制代码
window.addEventListener('nativeMessage', (e) => {
  const {method, requestId, data} = e.detail;

  // method 区分是哪个请求的响应
  if (method === 'getBuildingInfo') {
    // 拿到 buildingId 继续下一步
  } else if (method === 'getUserAllDoor') {
    // 拿到门禁列表
  } else if (method === 'doorOpen') {
    // 开门成功 显示结果
  }
});

4 个观察点(最容易混的地方)

观察点 谁 啥时候调
method 名字一致性 H5 method = handler 名 = sendMessage 参数 全程保持一致
requestId 唯一性 每次新请求生成 H5 发起时
ctx.sendMessage 是步骤 step7 原生 handler 完成后调 handler 内部
sendMessageToWebView 是步骤 step8 ctx.sendMessage 内部调 WebView.js 内

核心口诀 :「method 名字串起 H5 RN H5 三步,requestId 串起一次会话,handler 名 = sendMessage 的 method 参数」


五、11 个工具速查表

工具名 作用 内部调什么
getCloudTalkUserInfo 拿云对讲用户信息 api.getCloudTalkUserInfo()
queryBuildings 拿楼栋列表 api.queryBuildingsNew()
getUserAllDoor 拿门禁列表 api.getUserAllDoorNew()
verifyDoorHealth 验证开门权限 api.verifyDoorHealth()
doorOpen 执行开门 api.doorOpen()
getBuildingInfo 拿当前楼宇 直接从 redux 取
getBindingStatus 拿房屋绑定状态 直接从 redux 取
getToken 拿登录 token storage.getToken()
getUserInfo 拿用户信息 直接从 redux 取
getAgentContext 拿 agent 上下文 从 redux 拼
getServicePhone 拿服务中心电话 直接从 redux 取
callPhone 拨打电话 Linking.openURL tel ...

六、5 个观察口诀

口诀 1:JSBridge 三要素

复制代码
onMessage 接收 + injectJavaScript 发送 + requestId 关联

口诀 2:method 三名一致

ini 复制代码
handler 名 = H5 method = sendMessage 第一参数

口诀 3:业务数据回传路径

复制代码
sendMessageToWebView → webViewRef.injectJavaScript → dispatchEvent nativeMessage

口诀 4:3 个相似但不同

scss 复制代码
injectedJavaScript 是 prop 初始化用
injectJavaScript() 是方法 动态调用
sendMessageToWebView 是自定义函数 封装了方法调用

口诀 5:method 命名规范

erlang 复制代码
查数据用 getXxx 查列表用 queryXxx 执行动作用 verbXxx 跳转用 goXxx

七、面试常见 5 问速答

Q1:什么是 JSBridge?

A :JSBridge 是 JavaScript 与原生代码之间的通信桥梁。在 RN WebView 里:

  • H5 → 原生:window.ReactNativeWebView.postMessage → WebView onMessage
  • 原生 → H5:webViewRef.injectJavaScript → 派发 CustomEvent nativeMessage

Q2:onMessage / injectedJavaScript / injectJavaScript() 三者关系?

名称 性质 用途
onMessage WebView prop 接收 H5 发来的消息
injectedJavaScript WebView prop 初始化时注入静态配置
injectJavaScript() WebView 实例方法 任何时候动态注入 JS 业务数据回传

Q3:getToken 是步骤几?

A :同时是 step4 和 step7:

  • step4:handlers['getToken'](handler 名)
  • step7:ctx.sendMessage('getToken', ...)(sendMessage 第一参数)
  • step9:H5 收到的响应 method 字段是 'getToken'

三者必须同名,这就是 JSBridge 的 method 约定。

Q4:method 命名有什么规范?

A:4 类命名:

  • 查数据:getXxx(getToken getUserInfo getAgentContext)
  • 查列表:queryXxx 或 getUserXxx(queryBuildings getUserAllDoor)
  • 执行动作:verbXxx(doorOpen callPhone)
  • 跳转:goXxx(goBack)

Q5:为什么需要 requestId?

A :关联异步请求和响应 。H5 可能同时发多个 postMessage,原生处理完不一定按顺序返回,用 requestId 让 H5 知道这个响应是对应哪个请求。


面试前 5 分钟 :看第一节(10 步机制图)+ 第四节(method 命名规则)+ 第七节(5 问速答),足够应付 80% 追问。 被追问细节:看第二节(6 个深度问题)+ 第四节(完整开门案例)。

相关推荐
10年前端老司机1 小时前
我用 Vue3 + LangGraph 做了个心理咨询 AI,踩了 9 个坑后总结出来的实战经验
前端·langchain·agent
数据掘金1 小时前
A/B 实验分组参数回滚后还在生效?一次参数校验体系的重构复盘
前端
bmxy小明同学2 小时前
2026-10-09-token与成本
java·前端·数据库
neoooo2 小时前
🚀Claude Code 小技巧(二):找回会话,撤销修改
前端·人工智能·后端
今年下半年2 小时前
【文件上传】记录一次大附件上传的处理方案
前端·文件上传·内存溢出·分段上传
溪语流沙2 小时前
【每天一个CSS | Day21】落地页Hero动画的分镜表
前端·css
neoooo3 小时前
🚀Claude Code 小技巧(一):一键进入危险模式
前端·人工智能·后端
bmxy小明同学4 小时前
2026-10-11-幻觉治理
服务器·前端·javascript
Coder_张三4 小时前
iOS 26 适配
前端·ios·swift