electron通信 主进程与渲染进程/主进程与webview通信
一.electron主进程和渲染进程通信
进程通信分为异步和同步通信
官网有例子https://electronjs.org/docs/api/ipc-main,稍作解析
异步通信
//主进程中
const { ipcMain } = require('electron')
//主进程接收渲染进程发来的消息,回调中使用event.reply返回消息给渲染进程
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.reply('asynchronous-reply', 'pong')
})
//主进程向渲染进程发送消息, win为new BrowserWindow创建的窗口
const msgObj = { type: 'video', options: 'video_01' }
//方法一:
win.webContents.send('main', msgObj)
//方法二:
可以通过id定位到对应的渲染进程发送消息
const { webContents } = require('electron')
webContents.fromId(win.webContents.id).send('main', msgObj)
//-------------------------------------------------------------------
//渲染进程 (网页) 中
const { ipcRenderer } = require('electron')
//接收主进程回复的消息
ipcRenderer.on('asynchronous-reply', (event, arg) => {
console.log(arg) // prints "pong"
})
//渲染进程发送异步消息给主进程,
ipcRenderer.send('asynchronous-message', 'ping')
//接收主进程发送来的消息
ipcRenderer.on('main', (event, arg) => {
console.log(arg) // prints { type: 'video', options: 'video_01' }
})
分析
1.监听名称’asynchronous-message’和’asynchronous-reply’只要对应发送消息时起的名称即可,可以任意自定义字符串
2.消息监听的代码一定要先执行,才能在对应的消息发送后收到
3.消息内容也可以为对象/数字,通常使用对象,官网的例子直接用’ping’字符串只做简单演示
4.这里有个小技巧:send发送消息的时候自定义名称虽然自由,但是不推荐一种消息就起一个名字,我推荐名称尽量少,而使用发送的消息内容里 使用一个type属性来做消息类别的区分, 与使用websocket / postMessage 等处理消息内容时一样,自定义变量区分,方便统一管理
如下:
ipcRenderer.on('main', function (event, arg) {
const { type, ...argInfos } = arg;
switch (type) {
case 'video':
//other code...
break;
default:
break;
}
});
同步通信
注意:一般为了不阻塞进程,通常采用异步,官方建议异步,除非需要立刻回复消息,可以允许一定的阻塞等待结果,则采用同步.
//主进程中
const { ipcMain } = require('electron')
ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.returnValue = 'pong' //注意回复方式和异步的写法不同
})
//在渲染器进程 (网页) 中
const { ipcRenderer } = require('electron')
const replyValue = ipcRenderer.sendSync('synchronous-message', 'ping')
console.log(replyValue) // prints "pong"
二.electron主进程和webview通信
主进程和webview访客页通信的情况
友情提醒下:以下方法笔者写过是成功的,但是过了一段时间又不管用了,参考了 大神的博客https://www.cnblogs.com/lovesong/p/11180336.html后改为了websocket通信的方案替代了
后面笔者会再详细介绍 electron如何使用websocket代替ipc通信
不过主进程和webview通信可以尝试一下,因为理论上官方是支持的.
step1:
先在webview加载之前preload一个js, 其中把electron对象抛到webview所在访客页的全局,这样可以在访客页调用electron的api,即可以调用ipcRenderer与主进程通信
如下:
<webview id="webview" preload="./js/preload.js" disablewebsecurity nodeintegration autosize="on"></webview>
其中preload.js里挂载全局,并设置监听,然后实际的通信与主进程和渲染进程通信类似
const { ipcRenderer } = require('electron');
window.deskApi = {
electron: electron
};
//webview访客页监听主进程的消息
ipcRenderer.on('mainWeb', function (event, arg) {
const { type, ...argInfos } = arg;
switch (type) {
case 'music':
//other code...
break;
default:
break;
}
});
//webview访客页向主进程发消息
const ipcRenderer = window.deskApi.electron.ipcRenderer
ipcRenderer.send('mainWeb',{ type:'radio',option:'webmesage'})
step2:
主进程这边,还是推荐采用id的形式,在webview的渲染完成的时候提前把的id存储下来,然后需要的时候from(id)就可以
推荐方法:渲染进程中, 在webview dom-ready监听里,把webview的id发送到主进程存储
如下:
const webview = document.querySelector('#webview');
webview.addEventListener('dom-ready', (e) => {
///id存储起来,后续指定webview进行通信
ipcRenderer.send('asynchronous-message', { type: 'webviewContentId',webviewContentId: webview.getWebContentsId()})
}
step3:
最后就在主进程中获取到id, 与访客页通信
//主进程发消息到webview
let webviewContentId= 0;
//接受从渲染进程发来的webviewContentId
ipcMain.on('asynchronous-message', function (event, arg) {
const { type, ...argInfos } = arg;
switch (type) {
case 'webviewContentId':
webviewContentId = argInfos.webviewContentId
break;
default:
break;
}
});
//接受从webview访客页发来的消息
ipcMain.on('mainWeb', function (event, arg) {
const { type, ...argInfos } = arg;
switch (type) {
case 'radio':
//other code...
break;
default:
break;
}
});
//根据webview访客页的id发送消息
const { webContents } = require('electron')
const msgObj = { type:'music', options:'music_01' }
webContents.fromId(webviewContentId).send('mainWeb', msgObj)
三.electron渲染进程和webview通信
渲染进程与webview访客页通信和 主进程与webview访客页通信类似
在访客页中:
使用全局的ipcRenderer通信发消息,不过使用的方法有点区别,有两种用法:
用法一: sendToHost 就是发送到 webview访客页所在的html上,即渲染进程中.
用法二: sendTo 可以指定 进程实例webContents的Id,就像上面的那个webview id一样,主进程/渲染进程/webview访客页 都有id
参考官网: https://electronjs.org/docs/api/ipc-renderer
参考主进程和webview通信,一样的preload.js,electron抛全局,这里简写
例:
//webview访客页监听渲染进程的消息
ipcRenderer.on('renderWeb', function (event, arg) {
const { type, ...argInfos } = arg;
switch (type) {
case 'music':
//other code...
break;
default:
break;
}
});
//用法一: webview访客页向所在的渲染进程发消息
ipcRenderer.sendToHost('renderWeb',{ type:'radio',option:'webmesage'})
//用法二: webview访客页向任意渲染进程发消息,webContentsId自行存储/获取
ipcRenderer.sendTo(webContentsId, 'renderWeb',{ type:'radio',option:'webmesage'})
渲染进程中:
获取到当前主页中(如: index.html)的webvie元素, 使用这个webview实例,向webview发送消息
//渲染进程接受从webview访客页发来的消息
ipcRenderer.on('renderWeb', function (event, arg) {
const { type, ...argInfos } = arg;
switch (type) {
case 'radio':
//other code...
break;
default:
break;
}
});
//渲染进程向webview访客页发消息
const msgObj = { type:'music', options:'music_01' }
const webview = document.querySelector('#webview');
webview.send('renderWeb', msgObj)
总结
时间有限,行文粗糙,还请谅解.
不过基本思路方法都在那里了,其他细节大家先自行搜索下,后期得空笔者会上案例源码.大家有问题积极留言。
官网文档:https://electronjs.org/docs
https://appsoftea.com/zh/electron-ipcmain-ipcrenderer/
感谢: https://www.cnblogs.com/suzhen-2012/p/9932662.html