electron - Electron IpcRendrer 未将数据从 Main 发送到 HTML
问题描述
我正在创建一个类似于 WhatsAppWeb 的 WhatsApp 客户端。我使用 IPC 在 HTML 和 main 之间使用以下 preload.js 进行通信
const { ipcRenderer, contextBridge } = require("electron");
contextBridge.exposeInMainWorld("api", {
send: (channel, data) => {
// whitelist channels
let validChannels = ["toMain"];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
receive: (channel, func) => {
let validChannels = ["fromMain"];
if (validChannels.includes(channel)) {
ipcRenderer.on(channel, (_, ...args) => func(...args));
}
}
});
以下是main.js
const path = require("path");
const client = require("./src/client").instance;
const { app, ipcMain, BrowserWindow } = require("electron");
let win;
function createWindow() {
win = new BrowserWindow({
width: 1280,
height: 800,
icon: path.join(__dirname, "views", "images", "logo.png"),
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
enableRemoteModule: false,
preload: path.join(__dirname, "src", "preload.js"),
}
});
win.maximize();
win.loadFile(path.join("views", "login.html"));
win.webContents.openDevTools();
}
app.whenReady().then(() => {
createWindow();
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0)
createWindow();
});
});
app.on("window-all-closed", () => {
if (process.platform !== "darwin")
app.quit();
});
client.addListner("qr", (url) => {
// this works fine and logging the URL after page change using a console log prints a valid qrcode url
if (!client.isReady()) {
let logoFilePath = path.join(__dirname, "views", "images", "logo.png");
win.webContents.send("fromMain", {
event: "onQr",
args: {
url: url,
logoFilePath: logoFilePath
}
});
}
});
client.login();
ipcMain.on("toMain", (_, data) => {
let { event, args } = data;
switch (event) {
case "logout":
client.logout().then(() => client.login());
default:
break;
}
});
我有 2 个 HTML 页面 login.html 和 index.html 以下是解释应用程序顺序的屏幕截图。 login.html 的截图 以下是 login.html 中与主进程交互的脚本标签。
<script>
window.api.receive("fromMain", (data) => {
let { event, args } = data;
switch (event) {
case "onQr":
generateQrCode(args.url, args.logoFilePath);
break;
case "onReady":
window.location.replace("index.html");
break;
default:
break;
};
});
</script>
index.html 的截图如下是login.html中主进程接收和发送的script标签
$("#logoutBtn").click((event) => {
event.preventDefault();
window.api.send("toMain", {
event: "logout",
args: {}
});
// I think the problem may be here on page redirection becuase
it almost feels like the script doesn't run at all in login.html after being reloaded
window.location.replace("login.html");
});
按下注销按钮后,登录页面正常加载,后端进程正常生成二维码,但不再触发接收功能。尝试通过在预加载接收功能中添加控制台日志来检查发送功能是否是主进程正在工作,在控制台中会给出以下结果。
// preload after modification
const { ipcRenderer, contextBridge } = require("electron");
contextBridge.exposeInMainWorld("api", {
send: (channel, data) => {
// whitelist channels
let validChannels = ["toMain"];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
receive: (channel, func) => {
let validChannels = ["fromMain"];
if (validChannels.includes(channel)) {
// the console logs works fine
console.log(">>>>>>>>>>> recieving");
console.log(func);
// this line doesn't do anything in the second page load
ipcRenderer.on(channel, (_, ...args) => {
func(...args);
});
}
}
});
login.html 中控制台日志的屏幕截图 我想要实现的是注销后再次加载登录,应用程序序列重新开始,但是即使触发了接收功能,登录页面在重新加载后也没有从主进程接收任何内容成功导致我怀疑问题出在我使用 window.location.replace 重新加载页面的方式上
解决方案
我发现了这个问题,它与 IPCRenderer 或页面重新加载无关,而是我的错误。我没有将主进程中的客户端对象更新为新客户端,因此生成了二维码但从未发送过,因为旧客户端处于就绪状态。
// new main.js
const path = require("path");
// import the class instead of an instance to be able to create an new object whenever user logs out
let WhatsAppClient = require("./src/client");
const { app, ipcMain, BrowserWindow } = require("electron");
let win;
function createWindow() {
win = new BrowserWindow({
width: 1280,
height: 800,
icon: path.join(__dirname, "views", "images", "logo.png"),
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
enableRemoteModule: false,
preload: path.join(__dirname, "src", "preload.js"),
}
});
win.maximize();
win.loadFile(path.join("views", "login.html"));
}
app.whenReady().then(() => {
createWindow();
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0)
createWindow();
});
});
app.on("window-all-closed", () => {
if (process.platform !== "darwin")
app.quit();
});
// moved listners to a setup function to call it when ever creating a new client
const setupClientListners = (client) => {
client.addListner("qr", (url) => {
// the problem was here as I were using the old client object which had a ready state of true so the qr was generate but never sent to the HTML page
if (!client.isReady()) {
let logoFilePath = path.join(__dirname, "views", "images", "logo.png");
win.webContents.send("fromMain", {
event: "onQr",
args: {
url: url,
logoFilePath: logoFilePath
}
});
}
});
client.addListner("ready", () => {
client.isReady(true);
win.webContents.send("fromMain", {
event: "onReady",
args: {}
});
});
};
// setting up client
let client = new WhatsAppClient();
setupClientListners(client);
client.login();
ipcMain.on("toMain", async (_, data) => {
let { event, args } = data;
switch (event) {
case "logout":
await client.logout();
// delete old client and create a new one
delete client;
client = new WhatsAppClient();
setupClientListners(client);
client.login();
default:
break;
}
});
推荐阅读
- node.js - 与单独运行相比,为什么异步运行多个数据抓取任务需要更多时间?
- python - 从第一个值的唯一值创建嵌套列表
- linux - 在 Linux 中,“bash”命令何时获取 ~/.bash_profile 或 ~/.profile 文件?
- android - 如何将标头添加到来自 volley 库的请求中
- snowflake-cloud-data-platform - Snowflake Joining 2 table 不会同时加载两个表
- c++ - 像下面这样扩展内存是否安全
- android - Enable Debug Mode in Android Google Exposure API
- java - 检索会话属性并将其排序为字符串
- javascript - 确定元素在 JS 中的位置 - 移动端与桌面端
- javascript - 知道用户是否说了一些具体的话