当前位置: 首页 > Web前端 > HTML

【Electron】酷家乐客户端开发实践分享——流程沟通

时间:2023-04-02 18:20:52 HTML

作者:酷家乐PC客户端负责人钟丽原文地址:https://webfe.kujiale.com/electron-ku-jia-le-ke-hu-duan-kai-fa-shi-jian-fen-xiang-jin-cheng-tong-xin/酷家乐客户端:下载地址https://www.kujiale.com/activity/136文章背景:酷家乐客户端改版成功后在V12,我们积累了很多宝贵的经验和最佳实践。前端社区对Electron的了解比较少,所以希望以系列文章的形式分享这方面的内容。系列文章:【Electron】酷家乐客户端开发实践分享-入坑【Electron】酷家乐客户端开发实践分享-软件自动更新【Electron】酷家乐客户端开发实践分享-浏览器启动客户端【Electron】酷家乐客户端开发实践分享-进程通信【Electron】酷家乐客户端开发实践分享-下载管理器不定时更新...前言Electron中的进程其实就是电脑中的进程。我们先来看看什么是进程通信。进程间通信(IPC,Inter-ProcessCommunication)是指至少在两个进程或线程之间传输数据或信号的一些技术或方法。每个进程都有自己的一部分独立的系统资源。是孤立的。为了使不同的进程能够访问资源并相互协调工作,就有了进程间通信。一个Electron应用有一个主进程和多个渲染进程,渲染进程也可能嵌入多个webview。两者之间可能有沟通的需要,情况相当复杂。需要通信的对象主进程:使用ipcMain进行通信渲染进程:使用ipcRenderer和remote模块进行通信webview:一般禁用webview的node集成,然后使用preload获取ipcRenderer进行进程通信。//preload.jsconstelectron=require('electron');const{ipcRenderer}=electron;//在window上挂载ipcRenderer,webview里面的js可以获取这个模块.我们先看一个简单的例子:点击创建按钮创建一个新窗口。单击关闭按钮关闭这个新窗口。左边代码使用ipcRenderer/ipcMain进行通信,右边代码使用remote进行通信。实现的功能是一样的。从这个例子可以发现,使用ipcMain/ipcRenderer通信,业务逻辑同时存在于主进程和渲染进程的代码中。同时,为了通信,会产生大量的事件&事件处理器。使用远程通信,渲染进程直接获取主进程模块。而且使用远程通信不需要使用事件和回调函数,编写的代码清晰直观。主进程可以看作是模块提供者,渲染进程是模块消费者。渲染进程通过远程获取主进程的模块,实现业务逻辑。这样做有以下好处:主流程/渲染流程代码解耦,职责清晰,可维护性提高。渲染进程中的业务逻辑内聚,减少了主进程/渲染进程的冗余。下面来看看Electron进程通信在不同情况下的实现方式。主进程与渲染进程通信。主进程发送消息,渲染进程接收消息:主进程使用窗口的webContents发送消息,渲染进程使用ipcRenderer接收消息。//main.jsconstwin=newBrowserWindow();win.load('index.html');win.webContents.send('hello',{a:1});//index.html中的jsconst{ipcRenderer}=require('electron');ipcRenderer.on('hello',(e,data)=>{console.log(data);//打印出{a:1}})渲染进程发送消息,主进程接收消息:渲染进程使用ipcRenderer发送消息,主进程使用ipcMain接收消息。//main.jsconst{ipcMain}=require('electron');ipcMain.on('hello',(e,data)=>{console.log(data);//打印出{a:1}});//index.html中的jsconst{ipcRenderer}=require('electron');ipcRenderer.send('你好',{a:1});一般主进程与渲染进程通信时,大多是渲染进程需要获取主进程的模块。这时候建议使用remote进行通讯。//main.js//主进程不需要添加任何代码//index.html中的js,获取主进程模块const{remote}=require('electron');const{app,BrowserWindow,dialog,...}=远程;渲染进程与渲染进程之间的通信渲染进程也经常通信。例如在一个特定的场景中:在设置窗口中点击更改皮肤,需要通知所有窗口更新颜色和背景。最佳实践:渲染进程A通过remote模块获取目标窗口的webContents对象,然后通过webContents向目标窗口发送消息。目标窗口使用ipcRenderer监听事件。const{remote}=require('electron')constallWindows=remote.BrowserWindow.getAllWindows();//窗口A中的逻辑//1.第一步根据id获取目标窗口的webContents//title找到目标窗口,也可以使用其他方法consttargetId=1;consttargetTitle='目标窗口';//让targetWindow=allWindows.find(w=>w.id===targetId);lettargetWindow=allWindows.find(w=>w.title===targetTitle);//第二步,使用目标窗口的webContents发送消息targetWindow.webContents.send('theme-change','gray');//在目标窗口逻辑中,使用ipcRenderer监听事件//窗口接收到theme-change事件,改变窗口颜色。不需要关注事件从哪里发出,只需要关注接收到事件后做什么ipcRenderer.on('theme-change',(e,theme)=>{console.日志(主题);//灰色});还有一种传统的方法,不用remote,使用ipcMain进行通信,但是很多事件代码在主进程中会冗余。所以,和上面一样的原因,推荐使用remote。小例子//mian.js//对于事件转发,没有实际逻辑ipcMain.on('send-event-to-window',(e,id,eventName,...args)=>{BrowserWindow.getAllWindows().find(w=>w.id===id).webContents.send(eventName,...args);});//在窗口A内,向主进程发送一个事件consttargetId=1;ipcRenderer.send('send-event-to-window',id,'theme-change','gray');//目标窗口ipcRenderer.on('theme-change',(e,theme)=>{console.log(主题);//灰色});webview与渲染进程通信。嵌入式网页在客户端运行,也可以获得本地化能力。此时webview需要和渲染进程进行通信。文章开头提到,为了应用的安全,webview需要禁用节点集成。通过preload方法,在window上注入并挂载了一个ipcRenderer。webview发送消息,渲染进程接收消息:webview内部使用ipcRenderer.sendToHost发送消息。渲染进程获取webview的dom元素,监听dom元素的ipc-message事件接收消息//渲染进程获取webview的dom,接收事件constwebview=document.querySelector('webview')webview.addEventListener('ipc-message',(event)=>{console.log(event.channel);//hello});//在webview页面中,假装点击一个按钮并发送一个事件btn.onclick=()=>{window.ElectronIpcRenderer.sendToHost('hello')}渲染进程发送消息,webview接收消息:渲染进程使用webview.send发送消息。Webview使用内置的ipcRenderer来接收消息。//在webviewwindow.ElectronIpcRenderer.on('event-from-renderer',(e,data)=>{console.log(e,data);//{a:1}});//在渲染中processconstwebview=document.querySelector('webview')webview.send('event-from-renderer',{a:1})总结这三种通信方式是最基本的,排列组合也是很常见的他们是的,这个可以由开发者自己扩展。举个小例子:webview内部触发皮肤更换功能->通知渲染进程同步更新皮肤->渲染进程收到消息并与其他渲染进程通信->同步皮肤更新完成。最后欢迎大家在评论区讨论,技术交流&转介->zhongli@qunhemail.com