网页端和桌面端的electron通信Webview

1.electron使用Webview内镶嵌网页端

2.点击网页端触发electron的渲染进程

在网页端

javascript 复制代码
const sendDataToElectron = (data) => {
  console.log("🔥 [AiSystemEntrance] 准备发送数据到Electron:", data);

  // Electron webview 通信方法:使用特殊的 console 消息格式
  // 桌面端会监听 console-message 事件并解析这个特殊格式
  const message = `[ELECTRON_IPC]${JSON.stringify({
    type: "webview-message",
    data: data,
  })}[/ELECTRON_IPC]`;

  console.log(message); //使用console和桌面端通信

  // 也尝试其他方法作为备选--不过不生效,还是得是console通信
  try {
    // 尝试使用 postMessage (某些配置下可能工作)
    if (window.parent !== window) {
      window.parent.postMessage(
        {
          type: "webview-message",
          data: data,
        },
        "*"
      );
    }
  } catch (error) {
    console.error("❌ [AiSystemEntrance] postMessage 失败:", error);
  }

  console.log("📤 [AiSystemEntrance] 消息发送完成");
};

在electron端中的webview中使用handleWebViewReady

javascript 复制代码
 <webview
            key={tab.id}
            src={tab.url}
            className={`absolute inset-0 w-full h-[calc(100%-32px)] ${
              tab.active ? "visible" : "hidden"
            }`}
            webpreferences="nodeIntegration=true, contextIsolation=false"
            allowpopups="true"
            ref={(webview: WebViewElement | null) => {
              if (webview) {
                handleWebViewReady(webview);
              }
            }}
            onPageTitleUpdated={(e: WebViewTitleEvent) => {
              handleTitleUpdate(tab.id, e.title);
            }}
            onDidStartLoading={() => {
              console.log(`Started loading: ${tab.url}`);
            }}
            onDidFinishLoad={() => {
              console.log(`Finished loading: ${tab.url}`);
            }}
            onDidFailLoad={(e: WebViewLoadFailEvent) => handleLoadFail(e)}
          />

handleWebViewReady函数中使用原生 addEventListener 监听 console-message

javascript 复制代码
  const handleWebViewReady = useCallback(
    (webview: WebViewElement) => {
      webview.addEventListener("new-window", (e: NewWindowEvent) => {
        // console.log("New window requested:", e.url);
        addTab(e.url);
      });

      webview.addEventListener("will-navigate", (e: NavigationEvent) => {
        // console.log("Will navigate:", e.url);
      });

      webview.addEventListener("did-navigate", (e: NavigationEvent) => {
        // console.log("Did navigate:", e.url);
      });

      // 🔥 关键:使用原生 addEventListener 监听 console-message
      const handleConsoleMessage = (e: any) => {
        const message = e.message || "";
        
        // 检查是否是我们的特殊 IPC 消息格式
        if (
          message.includes("[ELECTRON_IPC]") &&
          message.includes("[/ELECTRON_IPC]")
        ) {
          try {
            // 提取 JSON 内容(处理 console.log 多参数格式:可能包含引号、空格等)
            const jsonStart =
              message.indexOf("[ELECTRON_IPC]") + "[ELECTRON_IPC]".length;
            const jsonEnd = message.indexOf("[/ELECTRON_IPC]");
            let jsonStr = message.substring(jsonStart, jsonEnd).trim();
            
            // 处理多种可能的格式:
            // 1. "[ELECTRON_IPC]" "{...}" "[/ELECTRON_IPC]"
            // 2. [ELECTRON_IPC] {...} [/ELECTRON_IPC]
            // 3. 移除首尾引号(单引号或双引号)
            jsonStr = jsonStr.replace(/^["']|["']$/g, "");
            // 移除可能的空格和换行
            jsonStr = jsonStr.trim();
            
            // console.log("🔍 [TabManager] 提取的 JSON 字符串:", jsonStr);
            
            const messageData = JSON.parse(jsonStr);

            // console.log("✅ [TabManager] 解析的 IPC 消息:", messageData);

            // 处理不同类型的消息
            if (messageData.type === "webview-message") {
              const data = messageData.data;

              // console.log("📦 [TabManager] 消息数据:", data);

              // 处理悬浮球点击事件
              if (data.type === "busEmitHandleFloatBallClick") {
          
                // 转发到主进程
                if (window.electron?.send) {
                // 渲染进程发送到主进程
                  window.electron.send("webview-open-legal-consultation", {
                    source: "webview",
                    action: "openLegalConsultation",
                    timestamp: Date.now(),
                  });
                } else {
                  console.error("❌ [TabManager] window.electron.send 不可用!");
                }
              } else {
                // 其他类型的消息也转发给主进程
                console.log("📤 [TabManager] 转发通用消息到主进程", data);
                window.electron?.send("webview-data", data);
              }
            }
          } catch (error) {
            console.error("❌ [TabManager] 解析 IPC 消息失败:", error);
            console.error("原始消息:", message);
          }
          return; // 已处理,直接返回
        }

        // 其他控制台消息正常输出
        console.log(`Webview console [${e.sourceId || 'unknown'}:${e.line || 'unknown'}]:`, message);
      };

      webview.addEventListener("console-message", handleConsoleMessage);
      console.log("✅ [TabManager] console-message 事件监听器已添加");
    },
    [addTab]
  );

重点,使用 React 的 onConsoleMessage 属性(可能不会触发)

javascript 复制代码
去掉代码:
onConsoleMessage={(e: WebViewConsoleEvent) =>
              handleConsoleMessage(e)
            }
使用原生 
webview.addEventListener("console-message", ...)
相关推荐
@大迁世界几秒前
07.React 中的 createRoot 方法是什么?它具体如何运作?
前端·javascript·react.js·前端框架·ecmascript
颜酱1 小时前
DFS 岛屿系列题全解析
javascript·后端·算法
战南诚1 小时前
VUE中,keep-alive组件与钩子函数的生命周期
前端·vue.js
发现一只大呆瓜1 小时前
React-彻底搞懂 Redux:从单向数据流到 useReducer 的终极抉择
前端·react.js·面试
霍理迪2 小时前
Vue的响应式和生命周期
前端·javascript·vue.js
发现一只大呆瓜3 小时前
React-路由监听 / 跳转 / 守卫全攻略(附实战代码)
前端·react.js·面试
竹林8185 小时前
在Web3前端用Node.js子进程批量校验钱包,我踩了这些性能与安全的坑
javascript·node.js
Kel6 小时前
深入剖析 openai-node 源码:一个工业级 TypeScript SDK 的架构之美
javascript·人工智能·架构
SuperEugene7 小时前
Vue3 模板语法规范实战:v-if/v-for 不混用 + 表达式精简,避坑指南|Vue 组件与模板规范篇
开发语言·前端·javascript·vue.js·前端框架