背景

由于某个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之间的通讯的更多相关文章

  1. 使用electron进行原生应用的打包(2)---主进程与渲染进程之间的通信

    上一篇讲了使用electron进行打包的配置相关文件,这篇主要讲electron中很重要的通信方式. 首先解释一个概念: electron打包的应用包含两个部分 electron的环境(node),也 ...

  2. electron 主进程,和渲染进程的通信

    ipcMain https://electronjs.org/docs/api/ipc-main 当在主进程中使用时,它处理从渲染器进程(网页)发送出来的异步和同步信息, 当然也有可能从主进程向渲染进 ...

  3. 17-7-20-electron中主进程和渲染进程区别与通信

    老规矩,先吐槽,再记录. 今天被上司教育了将近一个小时.因为之前自动更新的模块,我认为已经完成了,但是还有一些细节没有完善好,就一直一直的被教育~ 事情全部做完,提交以后关闭issue! electr ...

  4. Visual Studio Code调试electron主进程

    Visual Studio Code调试electron主进程 作者: jekkay 分类: electron 发布时间: 2017-06-11 14:56  一·概述 此文原出自[水滴石]: htt ...

  5. Electron结合React,在渲染进程中使用 node 模块

    Electron结合React,在渲染进程中使用 node 模块 问题 将create-react-app与electron集成在了一个项目中.但是在React中无法使用electron.当在Reac ...

  6. Android 跨进程渲染

    本项目用于验证 Android 是否能够跨进程渲染 View,最终实现了在子进程创建WebView,主进程显示的功能. 一.跨进程渲染的意义 有一些组件比如 WebView 如果在主进程初始化,会大大 ...

  7. C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 VC中进程与进程之间共享内存 .net环境下跨进程、高频率读写数据 使用C#开发Android应用之WebApp 分布式事务之消息补偿解决方案

    C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). ...

  8. Java线程与线程、进程与进程之间通信方式

    1.1 基本概念以及线程与进程之间的区别联系 关于进程和线程,首先从定义上理解就有所不同: 进程是具有一定独立功能的程序.它是系统进行资源分配和调度的一个独立单位,重点在系统调度和单独的单位,也就是说 ...

  9. Python并发编程03 /僵孤进程,孤儿进程、进程互斥锁,进程队列、进程之间的通信

    Python并发编程03 /僵孤进程,孤儿进程.进程互斥锁,进程队列.进程之间的通信 目录 Python并发编程03 /僵孤进程,孤儿进程.进程互斥锁,进程队列.进程之间的通信 1. 僵尸进程/孤儿进 ...

随机推荐

  1. ELINK编程器典型场景之多APP文件下载

    有些应用场合中,单MCU内会采用BootLoader+APP1+APP2的加载模式,程序启动时先进入BootLoader程序,依据设定条件跳转至APPx应用运行:为满足此类需求,设计多达5个程序文件( ...

  2. 图像滤镜艺术---Photoshop实现Instagram Amaro滤镜特效

    原文:图像滤镜艺术---Photoshop实现Instagram Amaro滤镜特效 本文是我收集的一些使用Photoshop来实现Instagram滤镜的一些内容,在这里跟大家分享一下,这些效果是完 ...

  3. 【Linux】简单明了查看内存使用和ubuntu的版本号及位数

    1.查看ubuntu的版本号:cat /etc/issue 2.查看系统是32位的还是64位:getconf LONG_BIT 3.查看内存使用 free free命令可以用来查看系统内存使用情况,- ...

  4. C#基础加强篇---委托、Lamada表达式和事件(中)

    2.Lamada表达式     C#共有两种匿名函数:匿名方法和Lamada表达式.在2.0之前的C#版本中,创建委托的唯一方法是使用命名方法.C#2.0中引入了匿名方法,匿名方法就是没有名称的方法. ...

  5. WebAPI增加Area以支持无限层级同名Controller

    原文:WebAPI增加Area以支持无限层级同名Controller 微软的WebAPI默认实现逻辑 默认实现中不支持同名Controller,否则在访问时会报HttpError,在网上找到了各种路由 ...

  6. 批处理(bat)实现SQLServer数据库备份与还原

    原文:批处理(bat)实现SQLServer数据库备份与还原 备份数据库.bat @echo off set path=%path%;C:\Program Files (x86)\Microsoft ...

  7. Windows RabbitMQ 安装

    操作系统 Win10  企业版 目标: 在win10上安装RabbitMQ 安装步骤 1.安装RabbitMQ需要先安装Erlang语言开发包,下载地址:http://www.erlang.org/d ...

  8. 使用MinGW编译Boost,MSVC编译Boost的几种链接方式 good

    1.下载Boost(http://www.boost.org) 我目前用的是1.61.0版本 2.将MinGW下的bin目录完整路径设置到系统环境变量Path中,保证cmd命令行能找到gcc,g++等 ...

  9. MSYS2 环境搭建,并整合Qt

    本机环境:Windows XP 32位MSYS2地址:http://sourceforge.net/projects/msys2/ 下载32位版本,地址:http://sourceforge.net/ ...

  10. sublime3使用笔记

    1.ctrl+n 新建一个文件: 2.alt+shift+数字 分屏显示: 3.ctrl+alt+down(向下键) 连选很多行的指定开始位置: 如图: 紧接着再按shift+right(选中需要更改 ...