electron-bridge

github链接 求star

Motivition

  • 如果想一套代码同时能跑在web环境和electron环境中,就需要在代码中先判断环境,再分别写对应的逻辑。每次写到electron环境下的逻辑,又要区分渲染进程和主进程,因为有些事只能渲染进程做,有些事只能主进程做。所以,我希望能将这些抽象出来,某个方法,只能在electron环境下被调用,并且不需要关心在什么进程下,web只要判断环境,调不同的方法就行,不需要关心和electron的交互。

  • 如果,我需要快速的开启另一个electron的项目,我希望我web里的代码能轻易的获取到electron的能力,而不是重新开始编写,这个时候,我希望有一层对electron能力的封装。

  • 团队内有些成员对web很熟悉,但是对electron不是很了解,如果加入项目,就需要去学习electron的知识,这个时候,如果能有一个库列出了所有electron能做的事,你只需要调用,无需关心它是怎么实现的,能很大程度提高开发效率。

Goals

  1. 给web注入适当的环境变量,让web知道自己的环境

  2. 给web注入一个对象,包含所有electron能做的事(包括主进程、渲染进程)

How to do

在load web页面的时候,有个webPreferences配置,我们在这里预加载一个js文件,就是electron-bridge.js

这个文件拥有node的能力,并且它是属于渲染进程的,所以它能做渲染进程里的事, 也能跟主进程通讯。

st=>start: start
op0=>operation: index.js去调用bridge.js暴露出来的方法, ElectronBridge.setFullScreen()
op1=>operation: bridge.js通过ipcRender告诉ipacMain做什么,并把回调暂存起来
op2=>operation:  主进程做完告诉bridge.js做完了,发送数据
op4=>operation:  bridge.js带上收到的数据,执行暂存的回调
op3=>operation:  bridge.js直接做完,触发回调
cond=>condition: bridge.js判断是不是主进程做的事?
e=>end: endst->op0->cond
cond(yes)->op1->op2->op4->e
cond(no)->op3->e

Let's do it

给web注入适当的环境变量

加载bridge.js

win = new BrowserWindow({width: 800,height: 600,show: false,webPreferences: {preload: path.join(__dirname, '../bridge/bridge.js'),plugins: true}
});

当我们启动electron的时候,主进程开始通知这个渲染进程,给渲染进程注入主进程的环境变量,再有渲染进程挂载到window对象上,这样web就能获取自己的环境信息

//bridge.jsconst {ipcRenderer} = require('electron');//监听主进程,设置环境变量
ipcRenderer.on('set-env', (event, msg) => {for (const key in msg) {window[key] = msg[key];}
});
//main.js
const {BrowserWindow, ipcMain} = require('electron');const win = new BrowserWindow({...});//获取创建好的window对象发送消息
win.webContents.on('did-finish-load', function() {win.webContents.send('set-env', { //设置web环境变量__ELECTRON__: true,__DEV__: true,__PRO__: false,__SERVER__: false,windowLoaded: true});
});

通过bridge.js 来调用主进程的方法

我们通过ipcRender给主进程发送一系列消息,包括做什么事情(eventName), 根据哪些参数(params),对外根据不同的事件暴露不同的方法,接受参数,和回调函数。

  • 先将回调函数放在 eventsMap上暂存起来,因为ipcRender不能发送函数,所有的信息会被序列化后再发送给主进程,所以,我们先生成一个时间戳,让 eventsMap[时间戳] = cb 并把时间戳一同发送过去,等一会儿,主进程通知渲染进程调用哪个时间戳函数

  • 通过'resist-event'频道, 发送参数,包括 eventName、params、timeStamp

//bridge.js
const {ipcRenderer} = require('electron');const eventsMap = {};//调用原生事件
function registEvent(eventName, params, cb) {//允许只传两个数据if (!cb) {cb = params;params = {};}//如果win还未readyif (!windowLoaded) {cb(new Error('window not ready'));return;}const stamp = String(new Date().getTime());const opts = Object.assign({eventName}, params, {stamp});eventsMap[stamp] = cb; //注册唯一函数ipcRenderer.send('regist-event', opts); //发送事件
}//进入全屏
function setFullScreen(cb) {registEvent(SET_FULL_SCREEN, cb);
}window.ElectronBridge = {setFullScreen
};

主进程监听‘resist-event’频道,做对应的事。我们会将所有主进程能做的事,放在eventsList对象下,当接受到渲染进程的通知,去eventsList找有没有对应的事能做,有,做完通过promise,或者通过回调函数,去在‘fire-event’频道通知,渲染进程,事情已经做完,并把数据传回去,包括 stamp(之前渲染进程传过来的,现在传回去,告诉渲染进程执行哪个回调函数) 、 payload(返回数据) 、err (错误信息)

//main.js
const {ipcMain} = require('electron');//监听对原生的调用
ipcMain.on('regist-event', (event, arg) => {const nativeEvent = eventsList[arg.eventName];if (nativeEvent) {const result =  nativeEvent(app, win, arg.params);if (isPromise(result)) {result.then(res => {event.sender.send('fire-event', {stamp: arg.stamp,payload: res});}).catch(err => {event.sender.send('fire-event', {stamp: arg.stamp,err});});} else {event.sender.send('fire-event', {stamp: arg.stamp,payload: result});}} else {event.sender.send('fire-event', {stamp: arg.stamp,err: new Error('event not support')});}
});

渲染进程监听‘fire-event’执行对应时间戳回调函数,并把主进程传过来的数据传给回调函数。触发完成后,删掉该回调函数。

//bridge.js//触发事件回调
ipcRenderer.on('fire-event', (event, arg) => {const cb = eventsMap[arg.stamp];if (cb) {if (arg.err) {cb(arg.err, arg.payload);} else {cb(false, arg.payload);}delete eventsMap[arg.stamp];}
});

如果是渲染进程能做的事,就不需要再和主进程通讯,可以直接完成触发回调

//bridge.js
const {webFrame} = require('electron');
//设置缩放比,只能在渲染进程中实现
function setZoomFactor(params, cb) {webFrame.setZoomFactor(params);cb && cb();
}window.ElectronBridge = {setZoomFactor
};

最终web中的js代码去调用bridge.js暴露出来的方法

// ../web/index.js$btn1.addEventListener('click', function() {if (__ELECTRON__ && ElectronBridge) { //electron 环境ElectronBridge.setFullScreen((err) => {if (err) return;console.log('done');});} else { //web 环境alert('不能设置全屏')//do something else}
});

实现electron-bridge相关推荐

  1. electron 桌面端业务中的小结(坑)

    文章目录 简介 安装electron依赖 本地数据库选择 indexedDB 封装的库 SQLite Lowdb electron-store electron-json-storage-alt.el ...

  2. 无头浏览器和抓取-解决方案

    本文翻译自:Headless Browser and scraping - solutions [closed] I'm trying to put list of possible solution ...

  3. Windows平台三大软件开发工具Delphi、WPF .NET Framework和Electron开发对比综述

    Embarcadero委托白皮书研究了Delphi,WPF .NET Framework和Electron之间用于构建Windows桌面应用程序的区别.由三个Delphi最有价值专家(MVP)志愿者, ...

  4. Electron、QT和JAVA PC桌面开发技术比较

    近几年PC桌面开发越来越多的被Electron,QT和Java技术占领.下面简单比较一下它们的优劣. Electron,势是开发用时快,社区轮子多,整合一下就能用.缺点是打包大,js计算弱. Java ...

  5. electron调用python_在Electron app中运行python脚本

    asar Whether to package the application's source code into an archive, using Electron's archive form ...

  6. 【亲测可用】用Electron和electron-builder打包Vue项目为exe可执行文件安装包(不推荐,个人觉得没有VNISEdit和NW好用,而且有些配置文件还挺脑残!)

    官方帮助文档http://www.electronjs.org/docs 有时候运行安装依赖包会很慢建议在(c)npm config edit之后弹出的.(c)npmrc记事本里面加入 electro ...

  7. Host Only、NAT和Bridge三种网络连接

    Host Only.NAT和Bridge三种网络连接 在安装好了Linux镜像之后,如何连接物理机和虚拟机呢?这就需要网络连接,网络连接有三种:HostOnly.NAT.Bridge,它们都可用于Gu ...

  8. 设计模式之桥接模式(Bridge)摘录

    23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式包括:1.FactoryMethod(工厂方法模式):2.Abstract Factory(抽象工厂模式):3.Sin ...

  9. 中key的用途_Micro Focus Operations Bridge Manager中的多个(RCE)漏洞

    从供应商的网站上. OBM作为操作桥为您的IT操作提供了一个单一的控制中心.所有来自服务器.网络.应用程序.存储和基础设施中其他IT孤岛的事件和性能管理数据都会被整合到一个先进的中央事件控制台的单一事 ...

  10. 使用Rust + Electron开发跨平台桌面应用 ( 一 )

    前言 近段时间学习了Rust,一直想着做点什么东西深入学习,因为是刚学习,很多地方都不熟悉,所以也就不能拿它来做编译器这些,至于web开发,实际上我并不建议拿这个来学习一门语言,大概有几个方面,一是w ...

最新文章

  1. 【python】使用python脚本将CelebA中图片按照 list_attr_celeba.txt 中属性处理(删除、复制、移动)
  2. NASA将天文数据转换为音频,来听听银河系的声音!
  3. oracle登录错误:ORA-28000: the account is locked 解决方法
  4. WPF 四种不同效果呼吸灯
  5. 几大主流国产浏览器统一屏蔽996.ICU!
  6. 用nohup执行python程序时,print无法输出
  7. 以太坊ETH不能转账,状态一直是pending状态原因和解决方法
  8. 病毒详解及批处理病毒制作:自启动、修改密码、定时关机、蓝屏、进程关闭...
  9. Android Studio全局搜索Ctrl+Shift+F占用解决
  10. CF #319 div 2 D
  11. C语言从放弃到入门,C语言,从放弃到入门
  12. 计算机如何驱动无线网络,无线网卡驱动怎么安装,小编教你怎么给电脑安装无线网卡驱动...
  13. 2020双十一,阿里云GRTN拉开直播和RTC技术下半场的序幕
  14. 高德地图自定义定位按钮后搜索周边
  15. Vue - 判断访问网页客户端设备是手机移动端还是 PC 电脑端(判断设备类型是否是移动端手机)
  16. NetSuite 使用库存盘点
  17. C语言之用循环来打印各种各样的图案
  18. 网站建设中如何打造最优seo优化页面
  19. 如何设计好系统异常处理
  20. Hololens开发学习笔记——TrackedHandJoint关节点详解

热门文章

  1. python中beautifulsoup是什么_Python中的BeautifulSoup – 获取类型的第n个标记
  2. 5_python基础—条件语句(三目运算符)
  3. git clone --recursive慢_Git使用之submodule
  4. hive 语句总结_HiveQL查询语句总结
  5. Mac安装MySQL后,设置初始密码
  6. Appfuse下载及安装步骤
  7. 《天天数学》连载12:一月十二日
  8. 【cogs2711】jump,二分答案+倍增套ST表
  9. 5.过滤器作为模板——寻找沃尔多、不相同的模板匹配_3
  10. iic总线从机仲裁_IIC协议底层原理超详细解析!示波器,逻辑分析仪多图预警