preload.ts 中的 contextBridge.exposeInMainWorld:ipcRenderer 接收到来自 main.ts 的消息但渲染器没有得到它

Posted

技术标签:

【中文标题】preload.ts 中的 contextBridge.exposeInMainWorld:ipcRenderer 接收到来自 main.ts 的消息但渲染器没有得到它【英文标题】:contextBridge.exposeInMainWorld in preload.ts: ipcRenderer receives the message from main.ts but the renderer doesn't get it 【发布时间】:2020-12-22 12:31:42 【问题描述】:

在一个 Electron-React-Typescript 应用程序中,我设法在预加载中通过 contextBridge.exposeInMainWorld 将消息从渲染器进程发送到主进程,但在返回的路上,来自主进程的处理输出实际上通过并到达 preload.ts,但它没有到达渲染器进程。 一定是真的“愚蠢”的东西,但我不知道“罪魁祸首”是什么。所以,我请求你的帮助。

preload.ts:

const 
  contextBridge,
  ipcRenderer
 = require("electron")


contextBridge.exposeInMainWorld(
  "api", 
      send: (channel, data) => 
          ipcRenderer.invoke(channel, data).catch(e => console.log(e))
      ,
      receive: (channel, func) => 
        ipcRenderer.on(channel, (event, ...args) => func(...args))
        //ipcRenderer.on(channel, (event, ...args) => 
          //console.log("ipcRenderer.on-args: ", args);
        //);
      
)

index.d.ts:

declare interface Window 
    api: 
      send: (channel: string, ...arg: any) => void;
      receive: (channel: string, func: (event: any, ...arg: any) => void) => void;
    

main.ts:

ipcMain.handle("path-to-url", (IpcMainEvent, path) => 
  console.log("received a request from viewerDemo");
  if (mainWindow) 
    let urlified = url.pathToFileURL(path);
    console.log("urlified = url.pathToFileURL(path) : ", urlified);
    console.log("urlified.href= ", urlified.href);
    console.log("urlified.pathname= ", url.pathToFileURL(path).pathname);
    mainWindow.webContents.on("dom-ready", () => 
      mainWindow.webContents.send("path-to-url", "ohhhhhhhhhhhhhhhh");
      mainWindow.webContents.send("path-to-url", url.pathToFileURL(path).pathname);
    );
  
);

渲染器进程(数据未正确显示的地方!):

viewerDemo.tsx

import * as React from 'react';
import Viewer from 'react-viewer';

let path_1 = './images/natural-scene.jpeg';
let url_path;

const pathToUrlFunc = (path): string => 
  console.log("pathToUrlFunc called");
  window.api.send("path-to-url", path);
  let urlPath;
  window.api.receive("path-to-url", (event, args) => 
    console.log("window.api.receive called!");
    console.log("window.api.receive-args[0]: ", args[0]);
    urlPath = args[0];
  );
  return urlPath;


function ViewerDemo() 
  const [ visible, setVisible ] = React.useState(false);

  let urlpath = pathToUrlFunc(path_1);
  console.log("urlpath: ", urlpath);

  return (
    <div>
      <button onClick=() =>  setVisible(true);  >show</button>
      <Viewer
      visible=visible
      onClose=() =>  setVisible(false);  
      images=[src: 'https://www.fotolip.com/wp-content/uploads/2016/05/Nature-Scenes-
21.jpg', alt: '']
      //images=[src: urlpath, alt: '']

      />
    </div>
  );


export default ViewerDemo;

主要我得到:path received from main: ./images/natural-scene.jpeg 而对于从主返回到渲染器的方式,我得到:Cannot read property '0' of undefined

如果在我放置的 api 的“接收”部分中的 contextBridge.exposeInMainWorld 中:

  receive: (channel, func) => 
    //ipcRenderer.on(channel, (event, ...args) => func(...args))
    ipcRenderer.on(channel, (event, ...args) => 
      console.log("ipcRenderer.on-args: ", args);
    );
  

我不再收到该错误,在 preload.ts 中出现了来自 main.ts 的正确消息,但渲染器进程仍然没有收到它:

【问题讨论】:

【参考方案1】:

您现在可能已经找到了这个问题的答案,但以防万一,也为了任何遇到这个问题的人的利益;虽然我无法运行代码来证明这是问题所在,但我认为这是预加载接收功能的问题:

ipcRenderer.on 代理方法仅使用 args 参数的传播调用您的“func”处理程序。但是在 viewerDemo.tsx 中,您传递给“receive”以被称为“func”的处理程序方法需要两个参数“event”和“args”。因此,您在 args 中传递的单个参数可能在“事件”参数中显示为单个元素数组。

要测试理论并希望能解决这个问题,请使方法保持一致。您可以在 viewerDemo.tsx 的处理程序中从

更改此行

window.api.receive("path-to-url", (event, args) =&gt; window.api.receive("path-to-url", (args) =&gt;

或在 preload.ts 中更改此行ipcRenderer.on(channel, (event, ...args) =&gt; func(...args))ipcRenderer.on(channel, (event, ...args) =&gt; func(event, ...args))

两者都应该解决问题。

【讨论】:

这就是问题所在。谢谢@Hargrovm 在 *** 中打开了一篇关于正确渲染第二个窗口的新帖子。你会这么好心看看吗?提前谢谢你:***.com/questions/65582139/…

以上是关于preload.ts 中的 contextBridge.exposeInMainWorld:ipcRenderer 接收到来自 main.ts 的消息但渲染器没有得到它的主要内容,如果未能解决你的问题,请参考以下文章

如何用ruby中的数组中的元素替换字符串中的单词?

如何将视图中的 javascript 代码中的对象列表传递给控制器​​中的操作方法

如何从账户 A 中的 Lambda(VPC 中的 Lambda)调用账户 B 中的 AWS Lambda 函数(VPC 中的这个 Lambda)

我可以在 apatch 中的 php 文件中播放位于硬盘中的文件路径中的视频吗?

子窗口访问父页面iframe中的iframe,top打开的子窗口访问父页面中的iframe中的iframe

为啥正文中的 javascript 函数优先于头部中的函数?