如何从NAPI后端向Electron主动发送数据?附代码示例
解决方案:NAPI主动向Electron发送数据
核心思路
通过传递回调函数给NAPI,让NAPI在需要主动发送数据时调用该回调,再由Electron主进程将数据转发给渲染进程。
代码修改步骤
1. 主进程文件(main.js)
保存窗口实例,并修改SimpleFunction的IPC处理逻辑,将回调传递给NAPI:
const { app, BrowserWindow, Menu, ipcMain, dialog } = require('electron'); const path = require('path'); const getPcapData = require('./NAPI/build/Release/operations'); let win; // 全局保存窗口实例,用于向渲染进程发消息 function createWindow() { win = new BrowserWindow({ width: 1920, height: 1080, minWidth: 500, minHeight: 500, maxWidth: 1920, maxHeight: 1080, webPreferences: { preload: path.join(__dirname, 'preload.js'), }, }); win.loadFile('src/HTML/index.html'); } app.whenReady().then(() => { createWindow(); ipcMain.handle('SimpleFunction', async (event, index) => { // 定义回调函数,接收NAPI传来的数据并转发给渲染进程 const sendCallback = (data) => { win.webContents.send('napi-data', data); }; // 将业务参数和回调传给NAPI getPcapData.SimpleFunction(index, sendCallback); return 'NAPI任务已启动'; // 返回调用状态,而非业务数据 }); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit(); });
2. 预加载文件(preload.js)
新增暴露监听NAPI数据的方法,保证渲染进程安全接收消息:
const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('api', { SimpleFunction: async (index) => { return await ipcRenderer.invoke('SimpleFunction', index); }, // 暴露监听NAPI主动推送数据的方法 onNapiData: (callback) => { ipcRenderer.on('napi-data', (event, data) => callback(data)); } });
3. 前端调用文件(scripts.js)
先注册消息监听,再触发NAPI调用,确保不会错过数据:
// 提前注册监听,接收NAPI主动发送的数据 api.onNapiData((data) => { console.log('收到NAPI数据:', data); // 此处编写业务逻辑,比如更新页面UI、处理数据等 }); async function ClickButtonEvent(currentID) { const result = await api.SimpleFunction(parseInt(currentID)); console.log(result); // 输出"NAPI任务已启动" }
4. NAPI文件(operations.cc)
修改SimpleFunction接收回调参数,并在SendToElectron中调用回调传递数据:
#include <node_api.h> #include <iostream> #include <cstdio> #define NAPI_CALL(env, call) do { napi_status status = (call); if (status != napi_ok) { const napi_extended_error_info *error_info = NULL; napi_get_last_error_info((env), &error_info); bool is_pending; napi_is_exception_pending((env), &is_pending); if (!is_pending) { const char *message = (error_info->error_message == NULL) ? "empty error message" : error_info->error_message; napi_throw_error((env), NULL, message); return NULL; } } } while (0) // 保存NAPI环境和回调函数(若需支持多并发,建议改用结构体封装) napi_env g_env; napi_value g_callback; void SendToElectron(int index) { // 示例:构造要发送的数据 char data_buffer[64]; sprintf(data_buffer, "NAPI主动推送:ID=%d的处理结果", index); // 将C字符串转为NAPI字符串 napi_value napi_data; NAPI_CALL(g_env, napi_create_string_utf8(g_env, data_buffer, NAPI_AUTO_LENGTH, &napi_data)); // 调用回调函数,将数据传递给Electron主进程 napi_value undefined; NAPI_CALL(g_env, napi_get_undefined(g_env, &undefined)); napi_value args[1] = {napi_data}; NAPI_CALL(g_env, napi_call_function(g_env, undefined, g_callback, 1, args, NULL)); } napi_value SimpleFunction(napi_env env, napi_callback_info info) { size_t argc = 2; // 现在接收两个参数:业务ID、回调函数 napi_value args[2]; int index = 0; // 获取传入的参数 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); // 转换业务ID为C++整数 NAPI_CALL(env, napi_get_value_int32(env, args[0], &index)); // 保存NAPI环境和回调函数,供SendToElectron使用 g_env = env; g_callback = args[1]; // 触发主动发送数据的逻辑 SendToElectron(index); // 返回undefined给Electron主进程 napi_value undefined; NAPI_CALL(env, napi_get_undefined(env, &undefined)); return undefined; } napi_value init(napi_env env, napi_value exports) { napi_value simpleFunction; napi_create_function(env, nullptr, 0, SimpleFunction, nullptr, &simpleFunction); napi_set_named_property(env, exports, "SimpleFunction", simpleFunction); return exports; } NAPI_MODULE(NODE_GYP_MODULE_NAME, init);
关键注意事项
- 全局变量
g_env和g_callback仅适用于单实例场景,若需支持多并发请求,建议将回调和环境封装到结构体中,通过参数传递给SendToElectron; - NAPI中传递的数据类型需与Electron侧兼容,若需发送复杂数据(如JSON对象),可在NAPI中构造对应的napi_value对象;
- 渲染进程需提前注册监听,避免NAPI发送消息时前端未准备好接收。
内容的提问来源于stack exchange,提问作者alx
相关产品推荐
相关产品推荐

