乐趣区

关于即时通信:IM跨平台技术学习五融云基于Electron的IM跨平台SDK改造实践总结

本文由融云技术团队分享,有订正和改变。

1、引言

Electron 凭借其绝对更低的研发老本投入、弱小的跨平台反对、领有基数宏大的 Javascript 开发者受众等劣势,在 PC 端跨平台桌面开发畛域异军突起,大受欢迎。
本文分享的是融云基于 Electron 的 IM 跨平台 PC 端 SDK 革新过程中所总结的一些实践经验,心愿对你有用。

  • 情谊提醒:如果您对 Electron 的根底概念还不太理解,建议您先从本系列文章的首篇《疾速理解新一代跨平台桌面技术——Electron》和第 2 篇《Electron 初体验 (疾速开始、跨过程通信、打包、踩坑等)》开始浏览,否则可能难以了解本文的无关内容。
    学习交换:

    - 挪动端 IM 开发入门文章:《新手入门一篇就够:从零开发挪动端 IM》
    - 开源 IM 框架源码:https://github.com/JackJiang2…(备用地址点此)

(本文已同步公布于:http://www.52im.net/thread-40…)

2、系列文章

本文是系列文章中的第 5 篇,本系列总目录如下:
《IM 跨平台技术学习(一):疾速理解新一代跨平台桌面技术——Electron》
《IM 跨平台技术学习(二):Electron 初体验(疾速开始、跨过程通信、打包、踩坑等)》
《IM 跨平台技术学习(三):vivo 的 Electron 技术栈选型、全方位实际总结》
《IM 跨平台技术学习(四):蘑菇街基于 Electron 开发 IM 客户端的技术实际》
《IM 跨平台技术学习(五):融云基于 Electron 的 IM 跨平台 SDK 革新实际总结》(* 本文)
《IM 跨平台技术学习(六):网易云信基于 Electron 的 IM 音讯全文检索技术实际》(稍后公布..)

3、本次革新的技术指标

针对本次革新,咱们须要达到以下 4 个技术指标:
1)需提供与传统桌面通信软件相匹配的能力反对;
2)需实现浏览器与 Electron 不同运行时代码的高度复用;
3)便于开发者构建多窗口、多过程的简单桌面端利用;
4)需同步适配同一 IM 端 SDK 的多个版本。
以下,咱们将逐条探讨这 4 个指标所有实现的具体技术内容。

4、技术指标 1:需提供与传统桌面通信软件相匹配的能力反对

相较于 B/S 架构的 Web 网页利用,咱们冀望可能在 Electron 环境下向开发者提供更为丰盛的本地化能力,以及比 Websocket(或 Comet)更高效的 Socket 实时双工通信通道。

借助这些本来在浏览器环境下不便实现的技术能力,来整体进步用户对于桌面端产品的应用体验,将 Electron 作为一个 C/S 架构软件运行平台的后劲施展到最大。(文言就是,咱们心愿借助 Electron 这个框架,将本来 Web 端的一些鸡肋能力,做到像原生富客户端一样)

5、技术指标 2:浏览器与 Electron 不同运行时代码的高度复用

因为 Electron 与规范 Web 利用领有简直雷同的技术生态,因而少数产品会要求前端代码工程兼顾浏览器与 Electron。也就是说,一套代码既要打包为传统桌面端利用(利用 Electron),又可公布为浏览器中运行的 Web 网页利用。基于此,咱们提供的 IM SDK 须要在两种不同的运行时环境下做到差别最小化,防止开发者编写冗余的平台兼容代码。(文言就是,尽可能在基于 Electron 的桌面端和纯 Web 网页端之间重用更多的代码,不然又得多撸一个全新的 Electron 端,这得多吃力)

6、技术指标 3:便于开发者构建多窗口、多过程的简单桌面端利用

Electron 通过对 IPC 能力的封装为桌面端利用开发提供了较欠缺的跨过程通信计划,借助此能力,开发者构建的桌面端利用也逐步趋于简单。比拟典型的如桌面端 IM 产品:通常用一个独立窗口做根底的 IM 聊天业务,一个窗口做历史聊天记录查问业务。当有音视频会议业务场景时,还须要再开一个窗口做会议业务。甚至有开发者提出了与每个聊天对象都放弃一个独立聊天窗口的需要(产品状态如 QQ)。
在这类需要下,长连贯状态维持、音讯同步变得异样简单,起因在于以下 3 个方面。
1)若每个过程窗口都维持独立长连贯,难免会呈现某一过程连贯与其余过程连贯状态不同步。且开发者需在各过程同时保护连贯状态,复杂度较高。同时还会造成服务的并发能力降落。
2)若仅有繁多主窗口进行连贯维持,其余窗口通过 IPC 能力将主窗口作为连贯代理,则须要在主过程、各渲染过程中保护简单的跨过程通信业务代码,从而推高我的项目整体的复杂度。
3)目前的 Electron 开发者绝大多数来自于 Web 开发者,既有编程思维是建设在浏览器页面内单过程单线程的利用模型下构建起来的,对于解决此类多过程模型的产品开发不足相干的教训积攒。为升高相似需要场景的业务实现复杂度,咱们须要在 PaaS 能力层面上解决多过程连贯共享、多过程音讯同步问题,让开发者在既有编程思维模式下将每个业务实现的更为顺畅。

7、技术指标 4:需同步适配同一 IM 端 SDK 的多个版本

咱们的既有 Web 端 IM SDK 存在一个端多个不同版本的状况(次要是为了兼容老用户,旧版本很难一刀切间接扔掉,只能新老版末同时并存)。各版本都有不同数量的客户积攒,且各版本 API 接口设计迥异,跨版本升级老本较高。思考到应用不同版本的客户将来将业务向 Electron 迁徙的可能性,咱们冀望通过架构设计的改良来防止既有客户做过多的集成代码批改,在确保既有客户不因版本升级而散失的前提下升高 Web 研发团队本身的多版本 SDK 保护老本。

8、本次革新的落地实际

针对下面章节中确定的技术指标,咱们将从以下 3 个方向着手落地实际:
1)剥离各版本的独特业务与对外差异性 API 定义;
2)Electron 与浏览器平台下 IM SDK 的辨别;
3)解决多过程音讯同步、多过程连贯共享问题。以下,咱们将逐条分享这 3 个方面的具体实际内容。

9、落地实际 1:剥离各版本的独特业务与对外差异性 API 定义

咱们的 IM SDK 各版本别离为不同的代码仓库独立保护,互无干系。(文言就是,所有端的 IM SDK 都是独立开发,从头造轮子)这导致所有的性能(包含行将开发的 Electron 桌面解决方案)都可能要在各个版本仓库上独自实现,不仅开发成本高,还会导致实现品质无奈保障、或代码实现不对立,同时也推高了产研后续流程的测试、上线等环节的老本。

▲ IM SDK 不同版本独立保护
基于前述技术指标 4 的要求,在既有现状下持续开发,就意味着须要在两个版本的根底上做不同实现,既不合乎程序员的代码审美,也影响团队整体的研发效率。(文言就是,如果又要从头造轮子切实太难受)为更好地达成技术指标 4,团队决定优先通过重构将既有业务分层,即各个版本所必须的业务代码形象下沉为 IM Engine 包,并为各个版本 IM SDK 别离实现不同的 API Layer 以便与既有线上版本接口对齐,这样既能够升高团队的研发老本,也能够满足既有线上客户后续的降级需要。

▲ 重构代码实现业务分层
实现业务分层后,对于 IM SDK 有依赖的其余产品如 RTC SDK,也都能够解脱对 IM SDK 接口的依赖而间接调用 Engine 层接口,业务层在拓展 RTC 业务时,也就无需再思考 IM SDK 的版本问题。

▲ 业务分层后的构造将保障拓展性
做分层的另一个思考还为了达成技术指标 2,将与业务层的交互限度在 API 层,在 Engine 中解决 Electron 与浏览器两种运行时下的代码差别,业务层只需关怀 IM SDK 的接口调用而无需关怀底层差别,确保业务层在两种运行时下只须要保护极少甚至无需保护兼容代码,便于业务层更专一于业务开发。

10、落地实际 2:Electron 与浏览器平台下 IM SDK 的辨别

在将 Engine 与业务层隔离后(见上一节),须要思考 Engine 在不同的运行时下的要害能力差异,并根据能力差异落实 Engine 的底层设计。
Electron 环境下的连贯、音讯存储等能力由 c++ 模块编写提供(即前面提到的 CppProto.node):

在浏览器与 Electron 平台下,从连贯治理、到音讯收发等实现形式迥异,团队须要对 Engine 包持续分层,通过 AEngine 抽象类来定义 IM Engine 的能力接口,并形象 APIContext 类用来治理 AEngine 的能力调用。
思考到纯 Web 利用构建尺寸问题,Electron 的能力实现代码不应被打包到规范 Web 页面内,因而还须要将 Electron 平台下的实现代码独自抽离进去作为一个独立包(即 ElectronSolution),作为可选模块由开发者抉择装置应用。

▲ Electron 相干的代码抽离为可选模块如上图所示,CppEngine 在 ElectronSolution 包中定义,其须要由开发者在 Electron 利用创立 BrowserWindow 实例时通过 webPreferences.preload 配置属性向渲染过程窗口预挂载。APIContext 在初始化 AEngine 实例时,优先检测 CppEngine 是否已定义。当发现有 CppEngine 定义时,则初始化 CppEngine 提供更丰盛的本地化能力,否则初始化 JSEngine。
就像上面的代码的展示的逻辑:

const engine: AEngine = typeofCppEngine !== ‘undefined’  
? newCppEngine()  
: newJSEngine()

11、落地实际 3:解决多过程音讯同步、多过程连贯共享问题

ElectronSolution 包截止目前的设计中,所有代码都运行在渲染过程内。这意味着每个过程彼此独立,都在保护独立的过程状态,无奈满足指标 3 中多过程状态同步、连贯共享的需要。为了解决该问题,须要将 CppProto.node 模块放到主过程,在主过程中实现连贯治理、音讯收发等能力,多个渲染过程通过 IPC 通信共享主过程状态。

▲ 多个渲染过程
通过 IPC 通信共享主过程状态为了达成技术指标 3 的要求,ElectronSolution 须要拆分为两个子包,即 Main 与 Renderer。
具体就是:
1)Main 包运行在主过程内,负责维持 CppProto.node 模块的调用,实现底层连贯治理、音讯治理等性能,同时通过 Electron 提供的 ipcMain 与各渲染过程维持通信;
2)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
└── renderer
│   ├── dist
│   │   └── index.js
│   ├── index.js
│   └── package.json
└── package.json
基于上述架构变动,当业务层须要在多个渲染过程中实现 IM 能力时,仅须要关注在各个过程中的 IM SDK 接口调用,由 ElectronSolution 解决多过程之间的状态同步问题。当开发者冀望由既有 Web 业务向 Electron 平台迁徙时,开发者也无需批改既有的 Web 业务代码,仅须要增量编写主过程代码相干性能实现,将 ElectronSolution 装置并集成到 Electron 桌面端利用中即可。
最终,咱们造成了以下这样的 IM SDK 整体构造:

12、将来的布局

除了上述 IM 相干业务,后续咱们还打算在 Electron 平台下晋升 RTC 的场景能力。目前,Electron 平台下由 Chromium 原始提供的 WebRTC 能力对于开发桌面级音视频应用软件来说绝对单薄,咱们有打算摸索借助 node.js 的拓展能力,提供更为底层的 WebRTC 能力拓展如音效、音质、视频特效等。

13、参考资料

[1] 疾速理解新一代跨平台桌面技术——Electron
[2] Electron 初体验(疾速开始、跨过程通信、打包、踩坑等)
[3] WebSocket 从入门到精通,半小时就够!
[4] Comet 技术详解:基于 HTTP 长连贯的 Web 端实时通信技术
[5] 一套海量在线用户的挪动端 IM 架构设计实际分享(含具体图文)
[6] Web 端即时通讯技术盘点:短轮询、Comet、Websocket、SSE
[7] 搞懂古代 Web 端即时通讯技术一文就够:WebSocket、socket.io、SSE
(本文已同步公布于:http://www.52im.net/thread-40…)

退出移动版