IM跨平臺技術(shù)學(xué)習(xí)(五):融云基于Electron的IM跨平臺SDK改造實踐總結(jié)

本文由融云技術(shù)團(tuán)隊分享吏够,有修訂和改動推正。

1顿颅、引言

Electron 憑借其相對更低的研發(fā)成本投入缸濒、強(qiáng)大的跨平臺支持、擁有基數(shù)龐大的 Javascript 開發(fā)者受眾等優(yōu)勢,在 PC 端跨平臺桌面開發(fā)領(lǐng)域異軍突起绍填,大受歡迎霎桅。

本文分享的是融云基于Electron的IM跨平臺PC端SDK改造過程中所總結(jié)的一些實踐經(jīng)驗,希望對你有用讨永。

* 友情提示:如果您對Electron的基礎(chǔ)概念還不太了解滔驶,建議您先從本系列文章的首篇《快速了解新一代跨平臺桌面技術(shù)——Electron》和第2篇《Electron初體驗(快速開始、跨進(jìn)程通信卿闹、打包揭糕、踩坑等)》開始閱讀,否則可能難以理解本文的有關(guān)內(nèi)容锻霎。

(本文已同步發(fā)布于:http://www.52im.net/thread-4060-1-1.html

2著角、系列文章

本文是系列文章中的第5篇,本系列總目錄如下:

IM跨平臺技術(shù)學(xué)習(xí)(一):快速了解新一代跨平臺桌面技術(shù)——Electron

IM跨平臺技術(shù)學(xué)習(xí)(二):Electron初體驗(快速開始旋恼、跨進(jìn)程通信吏口、打包、踩坑等)

IM跨平臺技術(shù)學(xué)習(xí)(三):vivo的Electron技術(shù)棧選型冰更、全方位實踐總結(jié)

IM跨平臺技術(shù)學(xué)習(xí)(四):蘑菇街基于Electron開發(fā)IM客戶端的技術(shù)實踐

IM跨平臺技術(shù)學(xué)習(xí)(五):融云基于Electron的IM跨平臺SDK改造實踐總結(jié)》(* 本文

《IM跨平臺技術(shù)學(xué)習(xí)(六):網(wǎng)易云信基于Electron的IM消息全文檢索技術(shù)實踐》(稍后發(fā)布.. )

3产徊、本次改造的技術(shù)目標(biāo)

針對本次改造,我們需要達(dá)到以下4個技術(shù)目標(biāo):

1)需提供與傳統(tǒng)桌面通訊軟件相匹配的能力支持蜀细;

2)需實現(xiàn)瀏覽器與Electron不同運(yùn)行時代碼的高度復(fù)用舟铜;

3)便于開發(fā)者構(gòu)建多窗口、多進(jìn)程的復(fù)雜桌面端應(yīng)用奠衔;

4)需同步適配同一IM端SDK的多個版本谆刨。

以下,我們將逐條討論這4個目標(biāo)所有實現(xiàn)的具體技術(shù)內(nèi)容归斤。

4痊夭、技術(shù)目標(biāo)1:需提供與傳統(tǒng)桌面通訊軟件相匹配的能力支持

相較于 B/S 架構(gòu)的 Web 網(wǎng)頁應(yīng)用,我們期望能夠在 Electron 環(huán)境下向開發(fā)者提供更為豐富的本地化能力官册,以及比?Websocket(或Comet)更高效的Socket實時雙工通信通道生兆。

借助這些原本在瀏覽器環(huán)境下不便實現(xiàn)的技術(shù)能力,來整體提高用戶對于桌面端產(chǎn)品的使用體驗膝宁,將 Electron 作為一個 C/S 架構(gòu)軟件運(yùn)行平臺的潛力發(fā)揮到最大鸦难。(白話就是,我們希望借助Electron這個框架员淫,將原本W(wǎng)eb端的一些雞肋能力合蔽,做到像原生富客戶端一樣)

5、技術(shù)目標(biāo)2:瀏覽器與Electron不同運(yùn)行時代碼的高度復(fù)用

由于 Electron 與標(biāo)準(zhǔn) Web 應(yīng)用擁有幾乎相同的技術(shù)生態(tài)介返,因此多數(shù)產(chǎn)品會要求前端代碼工程兼顧瀏覽器與 Electron拴事。

也就是說沃斤,一套代碼既要打包為傳統(tǒng)桌面端應(yīng)用(利用Electron),又可發(fā)布為瀏覽器中運(yùn)行的 Web 網(wǎng)頁應(yīng)用刃宵。

基于此衡瓶,我們提供的 IM SDK 需要在兩種不同的運(yùn)行時環(huán)境下做到差異最小化,避免開發(fā)者編寫冗余的平臺兼容代碼牲证。(白話就是哮针,盡可能在基于Electron的桌面端和純Web網(wǎng)頁端之間重用更多的代碼,不然又得多擼一個全新的Electron端坦袍,這得多費(fèi)勁)

6十厢、技術(shù)目標(biāo)3:便于開發(fā)者構(gòu)建多窗口、多進(jìn)程的復(fù)雜桌面端應(yīng)用

Electron 通過對 IPC 能力的封裝為桌面端應(yīng)用開發(fā)提供了較完善的跨進(jìn)程通訊方案捂齐,借助此能力蛮放,開發(fā)者構(gòu)建的桌面端應(yīng)用也逐漸趨于復(fù)雜。

比較典型的如桌面端IM產(chǎn)品:通常用一個獨(dú)立窗口做基礎(chǔ)的 IM 聊天業(yè)務(wù)奠宜,一個窗口做歷史聊天記錄查詢業(yè)務(wù)包颁。

當(dāng)有音視頻會議業(yè)務(wù)場景時,還需要再開一個窗口做會議業(yè)務(wù)挎塌。

甚至有開發(fā)者提出了與每個聊天對象都保持一個獨(dú)立聊天窗口的需求(產(chǎn)品形態(tài)如 QQ)徘六。

在這類需求下内边,長連接狀態(tài)維持榴都、消息同步變得異常復(fù)雜,原因在于以下3個方面漠其。

1)若每個進(jìn)程窗口都維持獨(dú)立長連接嘴高,難免會出現(xiàn)某一進(jìn)程連接與其他進(jìn)程連接狀態(tài)不同步。且開發(fā)者需在各進(jìn)程同時維護(hù)連接狀態(tài)和屎,復(fù)雜度較高拴驮。同時還會造成服務(wù)的并發(fā)能力下降。

2)若僅有單一主窗口進(jìn)行連接維持柴信,其他窗口通過 IPC 能力將主窗口作為連接代理套啤,則需要在主進(jìn)程、各渲染進(jìn)程中維護(hù)復(fù)雜的跨進(jìn)程通訊業(yè)務(wù)代碼随常,從而推高項目整體的復(fù)雜度潜沦。

3)目前的 Electron 開發(fā)者絕大多數(shù)來自于 Web 開發(fā)者,既有編程思維是建立在瀏覽器頁面內(nèi)單進(jìn)程單線程的應(yīng)用模型下構(gòu)建起來的绪氛,對于處理此類多進(jìn)程模型的產(chǎn)品開發(fā)缺乏相關(guān)的經(jīng)驗積累唆鸡。

為降低類似需求場景的業(yè)務(wù)實現(xiàn)復(fù)雜度,我們需要在 PaaS 能力層面上解決多進(jìn)程連接共享枣察、多進(jìn)程消息同步問題争占,讓開發(fā)者在既有編程思維模式下將每個業(yè)務(wù)實現(xiàn)的更為順暢燃逻。

7、技術(shù)目標(biāo)4:需同步適配同一IM端SDK的多個版本

我們的既有Web端 IM SDK 存在一個端多個不同版本的情況(主要是為了兼容老用戶臂痕,舊版本很難一刀切直接扔掉伯襟,只能新老版末同時并存)。

各版本都有不同數(shù)量的客戶積累握童,且各版本 API 接口設(shè)計迥異逗旁,跨版本升級成本較高。

考慮到使用不同版本的客戶未來將業(yè)務(wù)向 Electron 遷移的可能性舆瘪,我們期望通過架構(gòu)設(shè)計的改進(jìn)來避免既有客戶做過多的集成代碼修改片效,在確保既有客戶不因版本升級而流失的前提下降低 Web 研發(fā)團(tuán)隊自身的多版本 SDK 維護(hù)成本。

8英古、本次改造的落地實踐

針對上面章節(jié)中確定的技術(shù)目標(biāo)淀衣,我們將從以下3個方向著手落地實踐:

1)剝離各版本的共同業(yè)務(wù)與對外差異性 API 定義;

2)Electron 與瀏覽器平臺下 IM SDK 的區(qū)分召调;

3)解決多進(jìn)程消息同步膨桥、多進(jìn)程連接共享問題。

以下唠叛,我們將逐條分享這3個方面的具體實踐內(nèi)容只嚣。

9、落地實踐1:剝離各版本的共同業(yè)務(wù)與對外差異性API定義

我們的 IM SDK 各版本分別為不同的代碼倉庫獨(dú)立維護(hù)艺沼,互無干系册舞。(白話就是,所有端的IM SDK都是獨(dú)立開發(fā)障般,從頭造輪子)

這導(dǎo)致所有的功能(包括即將開發(fā)的 Electron 桌面解決方案)都可能要在各個版本倉庫上單獨(dú)實現(xiàn)调鲸,不僅開發(fā)成本高,還會導(dǎo)致實現(xiàn)質(zhì)量無法保證挽荡、或代碼實現(xiàn)不統(tǒng)一藐石,同時也推高了產(chǎn)研后續(xù)流程的測試、上線等環(huán)節(jié)的成本定拟。

▲ IM SDK 不同版本獨(dú)立維護(hù)

基于前述技術(shù)目標(biāo)4的要求耘眨,在既有現(xiàn)狀下繼續(xù)開發(fā)疼鸟,就意味著需要在兩個版本的基礎(chǔ)上做不同實現(xiàn),既不符合程序員的代碼審美,也影響團(tuán)隊整體的研發(fā)效率憎兽。(白話就是蜻势,如果又要從頭造輪子實在太難受)

為更好地達(dá)成技術(shù)目標(biāo)4读恃,團(tuán)隊決定優(yōu)先通過重構(gòu)將既有業(yè)務(wù)分層愕鼓,即各個版本所必須的業(yè)務(wù)代碼抽象下沉為 IM Engine 包,并為各個版本 IM SDK 分別實現(xiàn)不同的API Layer以便與既有線上版本接口對齊需曾,這樣既可以降低團(tuán)隊的研發(fā)成本吗坚,也可以滿足既有線上客戶后續(xù)的升級需求祈远。

▲ 重構(gòu)代碼實現(xiàn)業(yè)務(wù)分層

完成業(yè)務(wù)分層后,對于 IM SDK 有依賴的其他產(chǎn)品如 RTC SDK商源,也都可以擺脫對 IM SDK 接口的依賴而直接調(diào)用 Engine 層接口车份,業(yè)務(wù)層在拓展 RTC 業(yè)務(wù)時,也就無需再考慮 IM SDK 的版本問題牡彻。

▲ 業(yè)務(wù)分層后的結(jié)構(gòu)將保證拓展性

做分層的另一個考慮還為了達(dá)成技術(shù)目標(biāo)2扫沼,將與業(yè)務(wù)層的交互限制在 API 層,在 Engine 中處理 Electron 與瀏覽器兩種運(yùn)行時下的代碼差異庄吼,業(yè)務(wù)層只需關(guān)心 IM SDK 的接口調(diào)用而無需關(guān)心底層差異缎除,確保業(yè)務(wù)層在兩種運(yùn)行時下只需要維護(hù)極少甚至無需維護(hù)兼容代碼,便于業(yè)務(wù)層更專注于業(yè)務(wù)開發(fā)总寻。

10器罐、落地實踐2:Electron 與瀏覽器平臺下 IM SDK 的區(qū)分

在將 Engine 與業(yè)務(wù)層隔離后(見上一節(jié)),需要考慮 Engine 在不同的運(yùn)行時下的關(guān)鍵能力差異渐行,并依據(jù)能力差異落實 Engine 的底層設(shè)計轰坊。

Electron 環(huán)境下的連接、消息存儲等能力由 c++ 模塊編寫提供(即后面提到的 CppProto.node):

在瀏覽器與 Electron 平臺下祟印,從連接管理肴沫、到消息收發(fā)等實現(xiàn)方式迥異,團(tuán)隊需要對 Engine 包繼續(xù)分層蕴忆,通過 AEngine 抽象類來定義 IM Engine 的能力接口颤芬,并抽象 APIContext 類用來管理 AEngine 的能力調(diào)用。

考慮到純 Web 應(yīng)用構(gòu)建尺寸問題孽文,Electron 的能力實現(xiàn)代碼不應(yīng)被打包到標(biāo)準(zhǔn) Web 頁面內(nèi)驻襟,因此還需要將 Electron 平臺下的實現(xiàn)代碼單獨(dú)抽離出來作為一個獨(dú)立包(即ElectronSolution),作為可選模塊由開發(fā)者選擇安裝使用芋哭。

▲ Electron相關(guān)的代碼抽離為可選模塊

如上圖所示,CppEngine 在 ElectronSolution 包中定義郁副,其需要由開發(fā)者在 Electron 應(yīng)用創(chuàng)建 BrowserWindow 實例時通過 webPreferences.preload 配置屬性向渲染進(jìn)程窗口預(yù)掛載减牺。

APIContext 在初始化 AEngine 實例時,優(yōu)先檢測 CppEngine 是否已定義存谎。當(dāng)發(fā)現(xiàn)有 CppEngine 定義時拔疚,則初始化 CppEngine 提供更豐富的本地化能力,否則初始化 JSEngine既荚。

就像下面的代碼的展現(xiàn)的邏輯:

const engine: AEngine = typeofCppEngine !== 'undefined'

??? newCppEngine()

??: newJSEngine()

11稚失、落地實踐3:解決多進(jìn)程消息同步、多進(jìn)程連接共享問題

ElectronSolution 包截止目前的設(shè)計中恰聘,所有代碼都運(yùn)行在渲染進(jìn)程內(nèi)句各。

這意味著每個進(jìn)程彼此獨(dú)立吸占,都在維護(hù)獨(dú)立的進(jìn)程狀態(tài),無法滿足目標(biāo) 3 中多進(jìn)程狀態(tài)同步凿宾、連接共享的需求矾屯。

為了解決該問題,需要將?CppProto.node?模塊放到主進(jìn)程初厚,在主進(jìn)程中實現(xiàn)連接管理件蚕、消息收發(fā)等能力,多個渲染進(jìn)程通過 IPC 通信共享主進(jìn)程狀態(tài)产禾。

▲ 多個渲染進(jìn)程通過 IPC 通信共享主進(jìn)程狀態(tài)

為了達(dá)成技術(shù)目標(biāo)3的要求排作,ElectronSolution 需要拆分為兩個子包,即Main 與 Renderer亚情。

具體就是:

1)Main 包運(yùn)行在主進(jìn)程內(nèi)纽绍,負(fù)責(zé)維持 CppProto.node 模塊的調(diào)用,實現(xiàn)底層連接管理势似、消息管理等功能拌夏,同時通過 Electron 提供的 ipcMain 與各渲染進(jìn)程維持通信;

2)Renderer 包中定義 CppEngine 類履因,繼承自 Engine 包內(nèi)的 AEngine 抽象類障簿,依然通過 webPreferences.preload 用來作為主進(jìn)程的代理,通過 ipcRenderer 與主進(jìn)程維持通信栅迄。

▲ 拆分為Main與Renderer兩個子包

修改完成后站故,ElectronSolution 包的整體結(jié)構(gòu)基本確定。

以下列出 ElectronSolution 包關(guān)鍵目錄結(jié)構(gòu)供參考:

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

基于上述架構(gòu)變動毅舆,當(dāng)業(yè)務(wù)層需要在多個渲染進(jìn)程中實現(xiàn) IM 能力時西篓,僅需要關(guān)注在各個進(jìn)程中的 IM SDK 接口調(diào)用,由 ElectronSolution 處理多進(jìn)程之間的狀態(tài)同步問題憋活。

當(dāng)開發(fā)者期望由既有 Web 業(yè)務(wù)向 Electron 平臺遷移時岂津,開發(fā)者也無需修改既有的 Web 業(yè)務(wù)代碼,僅需要增量編寫主進(jìn)程代碼相關(guān)功能實現(xiàn)悦即,將 ElectronSolution 安裝并集成到 Electron 桌面端應(yīng)用中即可吮成。

最終,我們形成了以下這樣的IM SDK整體結(jié)構(gòu):

12辜梳、未來的規(guī)劃

除了上述IM相關(guān)業(yè)務(wù)粱甫,后續(xù)我們還打算在Electron平臺下提升RTC的場景能力。

目前作瞄,Electron 平臺下由 Chromium 原始提供的 WebRTC 能力對于開發(fā)桌面級音視頻應(yīng)用軟件來說相對薄弱茶宵,我們有計劃探索借助 node.js 的拓展能力,提供更為底層的 WebRTC 能力拓展如音效宗挥、音質(zhì)乌庶、視頻特效等种蝶。

13、參考資料

[1]?快速了解新一代跨平臺桌面技術(shù)——Electron

[2]?Electron初體驗(快速開始安拟、跨進(jìn)程通信蛤吓、打包、踩坑等)

[3]?WebSocket從入門到精通糠赦,半小時就夠会傲!

[4]?Comet技術(shù)詳解:基于HTTP長連接的Web端實時通信技術(shù)

[5]?一套海量在線用戶的移動端IM架構(gòu)設(shè)計實踐分享(含詳細(xì)圖文)

[6]?Web端即時通訊技術(shù)盤點(diǎn):短輪詢、Comet拙泽、Websocket淌山、SSE

[7]?搞懂現(xiàn)代Web端即時通訊技術(shù)一文就夠:WebSocket、socket.io顾瞻、SSE

(本文已同步發(fā)布于:http://www.52im.net/thread-4060-1-1.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末泼疑,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子荷荤,更是在濱河造成了極大的恐慌退渗,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蕴纳,死亡現(xiàn)場離奇詭異会油,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)古毛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進(jìn)店門翻翩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人稻薇,你說我怎么就攤上這事嫂冻。” “怎么了塞椎?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵桨仿,是天一觀的道長。 經(jīng)常有香客問我忱屑,道長蹬敲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任莺戒,我火速辦了婚禮,結(jié)果婚禮上急波,老公的妹妹穿的比我還像新娘从铲。我一直安慰自己,他們只是感情好澄暮,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布名段。 她就那樣靜靜地躺著阱扬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪伸辟。 梳的紋絲不亂的頭發(fā)上麻惶,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天,我揣著相機(jī)與錄音信夫,去河邊找鬼窃蹋。 笑死,一個胖子當(dāng)著我的面吹牛静稻,可吹牛的內(nèi)容都是我干的警没。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼振湾,長吁一口氣:“原來是場噩夢啊……” “哼杀迹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起押搪,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤树酪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后大州,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體续语,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年摧茴,在試婚紗的時候發(fā)現(xiàn)自己被綠了绵载。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡苛白,死狀恐怖娃豹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情购裙,我是刑警寧澤懂版,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站躏率,受9級特大地震影響躯畴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜薇芝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一蓬抄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧夯到,春花似錦嚷缭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽路幸。三九已至,卻和暖如春付翁,著一層夾襖步出監(jiān)牢的瞬間简肴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工百侧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留砰识,地道東北人。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓移层,卻偏偏與公主長得像仍翰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子观话,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內(nèi)容