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", ...)