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

融云IM在Electron平台上的设计实践

时间:2023-03-28 16:05:04 HTML

Electron以其相对较低的研发成本投入、强大的跨平台支持、庞大的Javascript开发者受众群体,在PC端桌面应用软件开发领域崭露头角..本文旨在分享融云IM在Electron平台上开发桌面SDK产品的实战经验。关注【融云全球互联网通信云】了解更多融云IM的Electron桌面解决方案目标1.提供与传统桌面通信软件相匹配的能力支持相较于B/S架构的网页应用,融云期望能够在Electron环境下,它为开发者提供了比Websocket(或Comet)更丰富的本地化能力和更高效的双工通信通道。借助这些在浏览器环境下不便实现的技术能力,可以整体提升桌面产品的用户体验,最大限度地发挥Electron作为C/S架构软件运行平台的潜力。2.Browser和Electron不同,运行时代码复用性高。因为Electron和标准的Web应用有着几乎相同的技术生态,所以大多数产品都会需要前端代码工程来兼顾Browser和Electron。也就是说,一套代码既可以打包为传统的桌面应用程序,也可以发布为运行在浏览器中的Web应用程序。基于此,作为PaaS能力提供的融云IMSDK需要尽量减少两种不同Runtime之间的差异,避免开发者编写冗余的平台兼容代码。3、方便开发者构建多窗口、多进程的复杂桌面应用Electron通过封装IPC能力,为桌面应用开发提供了较为完善的跨进程通信解决方案。有了这种能力,开发者构建的桌面应用程序也逐渐趋于复杂化。典型的桌面通讯产品通常使用一个独立的窗口用于基本的IM聊天服务,以及一个用于历史聊天记录查询服务的窗口;当有音视频会议业务场景时,需要另开一个窗口进行会议服务;甚至有开发者提出需要与每个聊天对象(QQ等产品形态)维护一个独立的聊天窗口。在这种场景下,长期连接状态的维护和消息同步变得异常复杂。原因是如果每个进程窗口都维护一个独立的长期连接,那么必然会出现某个进程连接与其他进程连接状态不同步的情况;而开发者需要在各个进程中同时维护连接状态,比较复杂;同时也会降低服务的并发度。如果只有一个主窗口进行连接维护,其他窗口通过IPC能力将主窗口作为连接代理,那么主进程和各个渲染进程都需要维护复杂的跨进程通信业务代码,从而增加项目的整体复杂性。当前的大多数Electron开发人员都来自Web开发人员。现有的编程思想都是基于浏览器页面单进程单线程的应用模型。处理此类多进程模型的产品开发缺乏相关经验。积累的经验。为降低类似场景下业务实现的复杂度,融云需要在PaaS能力层面解决多进程连接共享、多进程消息同步等问题,让开发者在现有的基础上更顺畅地实现各项业务编程思维模式。4、需要同步适配多个版本的融云IMSDK。融云现有的WebIMSDK版本较多,每个版本的客户积累量不同,每个版本的API接口设计差异很大,跨版本升级成本较高。高的。考虑到未来使用不同版本的客户有可能将业务迁移到Electron,我们希望通过架构设计的改进,避免对现有客户进行过多的集成代码修改,在保证现有客户不会因流失而流失的前提下版本升级降低Web研发团队自身的多版本SDK维护成本。目标落地推广方案1.剥离各版本通用业务和外部差异API定义。融云的IMSDK每个版本都是针对不同的代码仓库独立维护的,相互之间没有任何关系,这就导致所有的功能(包括即将推出的Electron桌面解决方案)可能要在每个版本仓库上单独实现,这不是不仅导致开发成本高,还会导致实现质量无保障,或者代码实现不一致,还会推高后续产研过程中的测试上线成本。(IMSDK不同版本独立维护)基于目标4的要求,在现有现状下继续开发意味着需要在两个版本的基础上实现不同的实现,这都不符合代码美学程序员的数量也不影响整个团队的研发效率。为了更好地实现目标4,团队决定优先通过重构对现有业务进行分层。将每个版本所需要的业务代码抽象到IMEngine包中,为每个版本的IMSDK实现不同的APILayer,以兼容现有有线版本的接口对齐,不仅可以减少团队的研发成本,还要满足现有在线客户的后续升级需求。(重构代码,业务分层)分层完成后,其他依赖IMSDK的产品,如RTCSDK,也可以摆脱对IMSDK接口的依赖,直接调用Engine层接口。业务层扩展RTC业务时,无需考虑IMSDK的版本。(保证可扩展性)分层的另一个考虑是实现目标2,将与业务层的交互限制在API层,在Engine中处理Electron和Browser运行时的代码差异,业务层只需要关心IMSDK的接口调用无需关心底层差异,保证业务层在两个运行时下只需要维护很少或不需要兼容的代码,让业务层可以更专注于业务开发。2.Electron和Browser平台下IMSDK的区别将Engine与业务层隔离后,需要考虑Engine在不同运行时的关键能力差异,基于能力差异。在Browser和Electron平台下,从连接管理到消息收发的实现方式都大不相同。团队需要继续对Engine封装进行分层,通过AEngine抽象类定义IMEngine的能力接口,抽象出APIContext类来管理AEngine能力。转移。考虑到纯Web应用的buildsize,Electron的capability实现代码不应该打包成标准的Web页面,所以也需要将Electron平台下的实现代码单独作为一个独立的包(ElectronSolution)作为可选模块来上给开发者选择安装和使用。(代码提取为可选模块)如上图所示,CppEngine定义在ElectronSolution包中,需要开发者在创建BrowserWindow实例时通过webPreferences.preload配置属性预加载到renderer进程窗口电子应用。APIContext在初始化AEngine实例时,首先检查CppEngine是否已经定义。当找到CppEngine时,初始化CppEngine以提供更丰富的本地化能力,否则初始化JSEngine。常量引擎:AEngine=typeofCppEngine!=='undefined'?newCppEngine():newJSEngine()3.解决多进程消息同步和多进程连接共享的问题在ElectronSolution包目前的设计中,所有的代码都运行在渲染进程中,也就是说每个进程相互独立,维护一个独立的进程状态,不能满足目标3中多进程状态同步和连接共享的要求。为了解决这个问题,需要将CppProto.node模块放到main中进程,并在主进程中实现连接管理、消息收发等能力,多个渲染进程通过IPC通信共享主进程的状态。(多个渲染进程通过IPC通信共享主进程的状态。)为了实现目标3的需求,ElectronSolution需要拆分成两个子包:Main和RendererMain包运行在主进程中,负责维护CppProto.node模块的调用,实现底层的Connection管理、消息管理等功能,同时通过Electron提供的ipcMain与各个渲染进程保持通信。Renderer包中定义的CppEngine类继承自Engine包中的AEngine抽象类,仍然通过webPreferences.preload作为主进程的代理。ipcRenderer与主进程(Main和Renderer两个子包)保持通信后,ElectronSolution包的整体结构就基本确定了。下面列出了ElectronSolution包的关键目录结构,以供参考。node_modules/@rongcloud/electron-solution├──index.js├──main│├──addon││├──binding│││└──electron-v{electron-version}-{platform}-{arch}.node││└──index.js│├──dist││└──index.js│├──index.js│└──package.json└──渲染器│├──dist││└──index.js│├──index.js│└──package.json└──package.json基于以上架构变化,当业务层需要在多个渲染进程中实现IM能力时,只需要关注每个进程中的IMSDK接口调用,多个进程之间的状态同步由ElectronSolution处理。当开发者期望从现有的web业务迁移到Electron平台时,开发者不需要修改现有的web业务代码,只需要增量编写主流程代码实现相关功能,将ElectronSolution安装集成到Electron桌面应用程序就是这样。整体架构展示了融云Electron平台的未来规划。作为安全可靠的全球互联网通信云服务商,融云在继续深耕IM相关业务的同时,还将继续打造平台下的RTC场景能力。目前Electron平台下Chromium原本提供的WebRTC能力对于开发桌面级的音视频应用来说还是比较弱的。融云将探索如何利用node.js的扩展能力,提供更底层的WebRTC能力,如音效、音质、Videoeffects等,除了更深入的能力扩展,融云还将提供全面的桌面级的应用开发框架,为开发者提供更全面的Electron能力包,并规范开发者的代码组织和脚本构建过程,让开发者可以轻松地在处理复杂的大型桌面应用时,更专注于业务本身。同时,融云始终坚持对技术的持续投入,不断夯实底层技术,壮大基石实力。不断探索Electron以外的前端技术,同时坚持自我迭代和技术精益求精,为开发者带来更实用易用的产品。