研究Electron主进程、渲染进程、webview之间的通讯
背景
由于某个Electron应用,需要主进程、渲染进程、webview之间能够互相通讯。
不过因为Electron仅提供了主进程与渲染进程的通讯,没有渲染进程之间或渲染进程与webview之间通讯的办法,所以只能寻找其他方案来解决。
研究一:ipcMain/ipcRenderer
Electron主进程与渲染进程的通讯,就是用ipcMain/ipcRenderer这两个对象。
// 在主进程中.
const { ipcMain } = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.reply('asynchronous-reply', 'pong')
}) ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.returnValue = 'pong'
}) //在渲染器进程 (网页) 中。
const { ipcRenderer } = require('electron')
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong" ipcRenderer.on('asynchronous-reply', (event, arg) => {
console.log(arg) // prints "pong"
})
ipcRenderer.send('asynchronous-message', 'ping')
不过只能ipcRenderer主动发送消息,ipcMain无法主动发送消息给ipcRenderer。
主进程如何主动发送消息给渲染进程?
如果渲染进程的窗口是用BrowserWindow打开的,那么可以通过webContents.send主动向窗口发送消息。
let win = new BrowserWindow({ width: 800, height: 600 })
win.loadURL(`file://${__dirname}/index.html`)
win.webContents.on('did-finish-load', () => {
win.webContents.send('ping', 'whoooooooh!')
})
那么如果想主进程主动向渲染进程发送消息,就可以将创建BrowserWindow的逻辑放在主进程里,所有实例都在主进程里维护,那么主动发消息的问题也就解决了。
渲染进程之间如何进行消息通讯?
Electron虽然没有提供渲染进程之间的通讯,但可以通过主进程中转来达到这个目的。
步骤:
1、ipcRenderer.send消息到主进程。
2、主进程接收到消息,再通过维护的BrowserWindow实例,轮询webContents.send给各个窗口。
3、渲染进程触发订阅主进程事件。
渲染进程与webview之间如何通讯?
由于被打开渲染窗口中,会使用到webview标签(类似iframe)嵌入页面,所以这里也需要互相通讯。
webview是一个标签,它有一个ipc-message事件接收渲染进程的消息,如下。
// In embedder page.
const webview = document.querySelector('webview')
webview.addEventListener('ipc-message', (event) => {
console.log(event.channel)
// Prints "pong"
})
webview.send('ping’) //在访客页。
const { ipcRenderer } = require('electron')
ipcRenderer.on('ping', () => {
ipcRenderer.sendToHost('pong')
})
必须明确一点的是,上面代码中webview监听ipc-message事件的代码是写在渲染进程中的,不是在webview自己页面代码里。这就有一个很尴尬的问题,事件是有了,但webview页面里并不知道。
经过几番尝试,确实无法在嵌入页面接收到事件。
结论
在Electron提供的功能里,只能做到主进程和渲染进程的互相通信,webview像个弃子一样被隔离开了。
研究二:c++插件
上一个方案走不通后,我又想到是否可以做一个c++插件来实现。
PS:http://nodejs.cn/api/addons.html
c++插件实现思路:
1、在插件里定义两个方法,一个listen(订阅事件),一个trigger(发布事件)。
2、在listen里,将订阅事件的上下文(Local<Context>)、事件名称、回调保存下来。
3、在trigger里,遍历保存的订阅信息,匹配事件名称,然后调用订阅信息中的回调。
这里关键的思想就是,在插件有个全局变量来保存各个进程的订阅信息,所有的进程都使用同一个实例对象(单例)。
但是在require插件时候,我发现每个进程都是各自一个实例,不是单例,做不到共享全局变量。
结论
因为require插件的实例不是单例,所以此方案也夭折了。
研究三:socket
在上面方法验证走不通后,最后选择socket方式来中转消息。
PS:https://www.npmjs.com/package/ws
//in main process
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8888 }); wss.on('connection', function connection(ws) {
ws.on('message', function incoming(data) {
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
});
}); //in render process or webview
const WebSocket = require('ws');
const busClient = new WebSocket('ws://127.0.0.1:' + busPort + '/'); busClient.on('message', function incoming(data) {
console.log(data)
}); busClient.send('hello world’);
事件订阅与发布就可以基于上面代码实现。
//in render process or webview
var busEvents = {}; const WebSocket = require('ws');
const busClient = new WebSocket('ws://127.0.0.1:' + busPort + '/'); busClient.on('message', function incoming(data) {
data = JSON.parse(data);
if(busEvents[data.eventName]){
busEvents[data.eventName].apply(this, data.args);
}
}); function listen(eventName, func) {
busEvents[eventName] = func;
} function trigger(eventName, args) {
busClient.send(JSON.stringify({
eventName,
args
}))
}
总结
Electron主进程、渲染进程、webview之间的通讯,只能通过socket实现。
本文为原创文章,转载请保留原出处,方便溯源,如有错误地方,谢谢指正。
本文地址 :http://www.cnblogs.com/lovesong/p/11180336.html
研究Electron主进程、渲染进程、webview之间的通讯的更多相关文章
- 使用electron进行原生应用的打包(2)---主进程与渲染进程之间的通信
上一篇讲了使用electron进行打包的配置相关文件,这篇主要讲electron中很重要的通信方式. 首先解释一个概念: electron打包的应用包含两个部分 electron的环境(node),也 ...
- electron 主进程,和渲染进程的通信
ipcMain https://electronjs.org/docs/api/ipc-main 当在主进程中使用时,它处理从渲染器进程(网页)发送出来的异步和同步信息, 当然也有可能从主进程向渲染进 ...
- 17-7-20-electron中主进程和渲染进程区别与通信
老规矩,先吐槽,再记录. 今天被上司教育了将近一个小时.因为之前自动更新的模块,我认为已经完成了,但是还有一些细节没有完善好,就一直一直的被教育~ 事情全部做完,提交以后关闭issue! electr ...
- Visual Studio Code调试electron主进程
Visual Studio Code调试electron主进程 作者: jekkay 分类: electron 发布时间: 2017-06-11 14:56 一·概述 此文原出自[水滴石]: htt ...
- Electron结合React,在渲染进程中使用 node 模块
Electron结合React,在渲染进程中使用 node 模块 问题 将create-react-app与electron集成在了一个项目中.但是在React中无法使用electron.当在Reac ...
- Android 跨进程渲染
本项目用于验证 Android 是否能够跨进程渲染 View,最终实现了在子进程创建WebView,主进程显示的功能. 一.跨进程渲染的意义 有一些组件比如 WebView 如果在主进程初始化,会大大 ...
- C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 VC中进程与进程之间共享内存 .net环境下跨进程、高频率读写数据 使用C#开发Android应用之WebApp 分布式事务之消息补偿解决方案
C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). ...
- Java线程与线程、进程与进程之间通信方式
1.1 基本概念以及线程与进程之间的区别联系 关于进程和线程,首先从定义上理解就有所不同: 进程是具有一定独立功能的程序.它是系统进行资源分配和调度的一个独立单位,重点在系统调度和单独的单位,也就是说 ...
- Python并发编程03 /僵孤进程,孤儿进程、进程互斥锁,进程队列、进程之间的通信
Python并发编程03 /僵孤进程,孤儿进程.进程互斥锁,进程队列.进程之间的通信 目录 Python并发编程03 /僵孤进程,孤儿进程.进程互斥锁,进程队列.进程之间的通信 1. 僵尸进程/孤儿进 ...
随机推荐
- 利用属性中设置、查看DataContext Command等
DataContext 1 2 3 示例 1 2 xaml代码自动生成 3
- jquery trim()的用法
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...
- 照片美妆---基于Haar特征的Adaboost级联人脸检测分类器
原文:照片美妆---基于Haar特征的Adaboost级联人脸检测分类器 本文转载自张雨石http://blog.csdn.net/stdcoutzyx/article/details/3484223 ...
- Resources.resx 未将对象引用设置到对象的实例
原文:解决使用DevExpress开发错误:未将对象引用设置到对象的实例 在使用DevExpress是总是会出现一些状况.这次同事在他的机器上调试完毕的代码发过来,却出现“未将对象引用设置到对象的实例 ...
- C#图片灰度处理(位深度24→位深度8),用灰度数组byte[]新建一个8位灰度图像Bitmap 。
原文:C#图片灰度处理(位深度24→位深度8) #region 灰度处理 /// <summary> /// 将源图像灰度化,并转化为8位灰度图像. /// </summary> ...
- 最小二乘法 good
最小二乘法也称为最小平方法,是一种数据优化技术,它通过最小化误差的平方和寻找数据的最佳函数匹配. 最小二乘法最初由高尔顿在创立回归分析的时候提出,现在已经成为探索变量间关系最重要的方法,最小二乘法根据 ...
- 2015新款 MacBook 用心的测评与试用. 最轻薄的Mac上市
2015新款 MacBook 不一样的测评与试用. 最轻薄的Mac上市了. 直击现场 <HTML开发MacOSApp教程> http://pan.baidu.com/s/1jG1Q58M ...
- Linux下卸载QT SDK
unbuntu下卸载QT方法一:you can remove it like this, those developers should add this somewhere ! like next ...
- delphi 在多线程中使用 CreateOleObject 导致失败(一定要使用CoInitialize和CoUninitialize,举例查询WMI)
原帖地址 http://bbs.csdn.net/topics/390481350 解决办法 procedure DisplayVideoInfo; var wmi, objs, obj : OleV ...
- 【聚沙成塔系列】之《UML九种图-包图、类图》
一.包 (一)相关概念: 1.包: 一个包=一层=一个命名空间=一个文件夹 2.包的命名: 简单名:王老二 路径名:中国.河北省.廊坊市.廊坊师范学院.信息技术提高班.九期班.王老 3.可见性: +公 ...