得物商家客服桌面端Electron技術實踐

語言: CN / TW / HK

1.業務背景

隨著公司業務的快速發展,商家客服也納入了我們的服務範圍,商家客服工作臺的定位是通過工具和資料服務商家,一站式解決使用者購買諮詢訴求。通過工具和運營策略協助商家提升服務品質,讓品牌商家有動力運營好潛在的客戶,從而達到提升使用者服務的目標。桌面應用的轉化在未來是客服產品的方向。

  • 已有web端聊天系統的前提下,商家客服為什麼要遷移桌面應用?

首先我們收到部分商家客服反饋:

640.png

  • 使用者是上帝,我們是很重視使用者的反饋的,所以首先我們想的是如何在web端解決這些問題,下面我們逐一分析下以上問題我們能不能在網頁端解決呢?

針對客服A同學問題:大多數客服職場的桌上型電腦是不會安裝音訊裝置,如果人家沒音訊,沒外音,我們能強迫他買個播放器嗎,那肯定是不能的,如果是自營客服還有點處理方案,真需要,公司可以統一採購,但是ToC的顯然不能強制做什麼事情,所以此問題無解。

針對客服B同學問題:這句話怎麼理解呢,是這樣的,在一屏既有web瀏覽器,又有其他應用如飛書之類的PC應用疊著放,web notification通知由於是瀏覽器級別的,提醒不到最上層,瀏覽器的提醒確實有點弱(看不到提醒會影響到客服的首響,首響會影響客服的績效,咱公司對於使用者的服務效率是比較嚴格的),所以此問題無解。

針對客服C同學問題:em。。。好的,您說的對,web網頁給商家客服的感覺就是我們平臺有點趕不上形勢。。。

基於上面的一些場景,想必大家已經對為何做桌面應用有個初步的瞭解,下面以一張圖來看下web應用跟桌面應用的區別。

6401.png

2.技術選型

  • 為什麼會選擇Electron而不是其他應用開發框架?

2.1 Electron架構簡介

6402.png

Electron的構成主要是上面的3個大模組,每個模組各司其職,讓Electron有了桌面應用的能力。

  • Chromium:可以為Electron提供UI渲染能力,再加上Chromium本身就是跨平臺的,所以也不用考慮程式碼的相容性。只要有Chromium,就能用JavaScript,HTML,CSS這些前端開發工程師所熟知的三劍客來開發頁面。

  • Node.js:Chromium並不具備原生GUI操作的能力,所以Node.js正好補足了這個能力,能夠呼叫作業系統的底層 API,比如path、fs、crypto 這些模組,甚至能整合C++。

  • Native APIs:Native API讓Electron有了跨平臺和桌面端的原生能力,比如說它有統一的原生介面,視窗、托盤這些。

2.2 Electron與其他框架的區別

下面是Electron與Native、QT、NW應用的對比圖:

![截圖20230131 15.49.19.png](https://cdn.poizon.com/ctoo/013115/截圖2023-01-31 15.49.19.png)

  • Native(C++/C#/Objective-C)不管從原生體驗、包的體積、效能方面來說都是最佳的選擇,但是開發門檻高,迭代速度慢。

  • QT是基於C++的跨平臺開發框架,跨平臺應用十分廣泛(Mac、Windows、ios、Android、Linux、嵌入式),眾所周知的WPS就是用QT開發的。效能很好,甚至於可以媲美原生的體驗,但是整體門檻還是比較高的。

  • Web技術的代表Electron 和 NW.js ,相比之前選擇Electron,Electron有非常活躍的社群,有102k star,有Atom、vscode這樣的大型應用都是基於Electron開發的,效能相比於natvie是肯定要差一些,但綜合來看,Electron是作為開發桌面應用的目前首選。

  • 值得一提的是Flutter desktop,從渲染原理看flutter是skia自繪效能優於Electron,但問題還是穩定性和生態。Electron由於是nodejs+chromium,前端的生態可以直接用,所以Flutter desktop就不納入考慮範圍的,但值得關注。

除了以上這些,最主要的一點:Electron能快速交付,業務層複用web系統的程式碼,只需要關注主程序就好了,並且也能滿足業務需要的系統級別的一些功能。

6403.png

3.技術實現

3.1 專案架構

6404.png

首先介紹下Electron框架裡面兩個重要的概念主程序和渲染程序。

主程序:主要負責建立和管理BrowserWindow例項以及應用程式事件。它可以執行註冊全域性快捷方式,建立系統選單和對話方塊,響應自動更新事件等操作。主程序以及所有Node.js模組中都提供了一部分Electron API。

渲染程序:渲染過程負責執行應用程式的使用者介面,渲染程序中提供了所有DOM API,Node.js API和Electron API的子集。

6405.png

如上面截圖,開啟Electron專案之後會有多個程序,一個專案有且只有一個主程序,建立視窗等有關係統事件寫在主程序中進行,但是渲染程序可能有多個。

那為什麼會有多個渲染程序呢?

Electron應用是Chromium核心,所以多程序的架構也來源於Chromium,Chromium會單獨執行每個標籤,任何一個標籤頁崩潰了都不會影響到其他標籤。因此,每個程序在自己的空間中執行,由作業系統排程。如果某個程序觸發了無限迴圈,也不會導致整個應用down掉。

在上文說到兩個字“遷移”,是的,我們在開發桌面應用之前有非常成熟的web端商家客服聊天系統了,所以我們在開發桌面應用的時候大多數時候是關心主程序的,渲染程序並不太需要關心。

3.2 主程序功能模組

3.2.1 通訊模組

主要是呼叫Electron框架本身的API以及通用方法的封裝。

6406.png

主程序到渲染程序的通訊:

640.jpg

渲染程序到主程序的通訊:

有兩種方案,一種是在主程序開啟了nodeIntegration: true之後在渲染程序裡面可以使用window.require('Electron')來引入寫通訊相關程式碼

6401.jpg

一種是需要在主程序編寫preload.js,在初始化視窗的時候引入

6402.jpg

通訊的同步和非同步問題

  • 【非同步】渲染程序->傳送->主程序

6403.jpg

  • 【同步】渲染程序->傳送->主程序

6404.jpg

3.2.2 選單模組

主要是呼叫Electron框架本身的API,滿足快速擴充套件選單功能以及自定義選單功能。

6405.jpg

但是商家客服專案沒用到原生選單,而是用了自定義的選單。

沒有使用原生選單的主要原因是:

  • 原生選單樣式較死板,不能調整;

  • 自定義編寫選單能有各種自己想要的功能,可控制其展示。

3.2.3 托盤模組

托盤屬於系統級的操作,所以是在主程序中設定的。在開始之前需要注意的地方,設定托盤必須在程式ready之後。實現較簡單,程式碼如下:

6406.jpg

3.2.4 異常處理模組

主要呼叫Electron框架本身API,結合Node.js API,檢測系統異常後自動重新整理並上報,渲染程序的異常已經使用sls&arms處理,主程序的異常主要是通過Electron的crashReporter API來記錄日誌。

6407.jpg

上面提交引數有幾個需要注意的點:

  • submitURL 是以post方式上傳

  • extra 一個你可以定義的物件,附帶在崩潰報告上一起傳送 . 只有字串屬性可以被正確傳送,不支援巢狀物件

3.3 渲染程序功能模組

渲染程序的程式碼大部分跟商家客服web端一致,很多隻是遷移即可。

3.3.1 登入改造

登入資訊本地化,在登入成功的時候,把賬號資訊快取,下次開啟應用的時候客服無需再重新輸入,直接從快取獲取即可。

6407.png

3.3.2 靜態資源

傳統Web應用,將專案程式碼部署伺服器,專案執行時,訪問的是伺服器靜態資源,現在版本釋出流程,走的是cdn資源,總而言之都是通過網路獲取。

6408.png

Electron提供將靜態資源打包到安裝程式,在安裝時,將專案檔案同步安裝到使用者電腦,使其具備訪問本地檔案,減少了請求佔用資源,一定程度上也能改善因網速問題導致的靜態資源不能實時獲取,頁面白屏問題。

6408.jpg

3.3.3 資料儲存

Electron應用裡面的資料儲存是通過Electron-store第三方庫來實現的,實現比較簡單,如下:

6409.jpg

3.3.4 渲染程序打包

這塊為什麼要單拎出來講渲染程序打包呢,是因為web專案遷移變成應用渲染程序的時候不能像web應用一樣直接打包,需要調整請求API程式碼,API字首需要區分本地除錯和應用環境:

6409.png

使用Electron, 將專案打包成離線應用。使用file協議,在本地讀取靜態資源。但是ajax請求如果用相對路徑,打包之後,會直接找到根目錄,如下截圖:

64010.png

所以打包的時候需要給ajax提供完整的url路徑。

4.技術挑戰

在從0到1搭建商家客服桌面端的過程中,遇到了很多的問題,Electron社群雖然很活躍,但是不一樣場景遇到的問題,幾乎找不到對應的解決方案,所以很多都是在探索過程中不斷的去完善。這裡主要圍繞釋出構建流程和安全性來講下,我們是怎麼解決的。

4.1 安全性問題

Electron客戶端的安全問題也是非常重要的,那都遇到了哪些安全問題以及我們又是如何解決的呢,具體如下:

  • 渲染程序XSS:Electron實現的桌面端軟體渲染層的原理實際是通過chrome核心渲染的,同樣存在XSS注入的風險。舉個例子:在html頁面中可以執行命令:<img/src=x οnerrοr="require('child_process').exec('gnome-calculator')"> ,就可以開啟當前作業系統的計算器。接入了公司統一的XSS治理方案,該問題即得到解決。

  • 使用者認證資訊洩漏問題:商家客服桌面端登入呼叫商家的授權介面,APP閘道器有校驗,可以確保登陸沒有問題;

  • 本地快取明文讀取問題:本地資料洩漏,例如:indexDB、localStorage、sessionStorage等,我們主要用加密和解密演算法對本地快取資訊進行處理。

沒有絕對的安全,我們能做的就是儘可能的提高安全門檻,過程中我們也積極同公司的安全部門進行溝通,讓他們排查桌面端釋出之後的安全漏洞,最終驗證都是滿足安全標準,符合釋出的條件。

4.2 釋出構建流程

應用釋出涉及到渲染程序和主程序,渲染程序主要是負責給主程序提供渲染包,主程序使用Electron-builder庫來打包部署所釋出的包。

64011.png

前面已經說過,Electron的好處是可以無縫整合web端的業務邏輯程式碼,這裡上圖左邊紅色的是web端構建出的產物,我們會把這部分構建產物同步到主程序的app/render目錄下,即渲染程序目錄,這樣在打包應用包的時候,就能整合渲染程序的業務邏輯,而不需要維護兩份web端的程式碼。

此方案還存在不少的缺陷,由於生產構建環境需要window環境,所以暫時不支援在遠端打包,目前都是在本地window機器上打出完整的包之後再上傳到CDN,商家客服通過載入CDN的更新包來替換本地安裝檔案,實現軟體的本地安裝。

4.3 應用更新問題

應用開發離不開“更新”這個話題,比如飛書應用會時不時彈出一個更新視窗,讓你選擇是否更新,商家客服在推廣桌面應用之後,也存在更新這個問題。在業務快速發展的同時,如何將業務需求更好的同步給商家使用,這是商家客服桌面應用面臨的最大的挑戰。

4.3.1 全量更新

4.3.1.1 手動下載安裝

最基礎的更新模式,主要思路是在開啟app(其他時候也行,我們業務主要是開啟app的時候)的時候訪問遠端的json檔案,檔案內容包含版本號,更新內容等等最新版本的資訊,拿到遠端版本號會跟本地應用版本號做比較,如果版本號不一致,就詢問使用者是否更新,需要更新的話會下載到本地,使用者手動點選安裝即可。這個更新方式不推薦使用,如果你的應用一年更新一次,ok,是可以這麼做的。

64012.png

4.3.2 增量更新

在網速快的情況下,全量更新跟增量更新幾乎是沒有區別的。但是網速慢的情況下它倆之間的差距會被放大,使用者體驗不是很好。我們不能想當然的以為所有使用者網速都很好,這是不現實的,所以不管是PC應用還是移動端應用,大多數情況下是需要做增量更新。下面表格是網速不一樣情況下的下載耗時對比:

WeChate37b6a37cfe5899d3d525368ea1b1270.png

4.3.2.1 electron-updater

現在就開始介紹在商家客服應用(windows應用)中是怎麼實現增量更新功能的。

更新在大的分類上區分全量以及增量更新,在每個小分類裡面也區分強更新,弱更新(業務上的區分,底層實現沒區別)。簡單來說,強更新指的是使用者必須更新,不更新將無法使用系統功能,弱更新指的是使用者想要的時候再去觸發應用的更新,完全由使用者自主選擇。

64013.png

更新流程

64014.png

其中electron-updater作用於“更新應用”這個節點,主要是依賴新舊版本blockmap檔案的對比來實現增量更新。下面截圖為electron-builder打包出來的release包,每次打包都會有對應的blockmap檔案。

64015.png

electron-updater更新實現主要流程:

  • 生產的blockmap檔案:

1.使用7z壓縮安裝包

2.讀取安裝包的header

3.計算出每個file的offset和end得到相應的hash生產blockmap

  • 使用blockmap檔案:

1.下載雲上的blockmap檔案跟本地blockmap檔案對比,從上面截圖可以看出blockmap檔案很小,所以下載並不會對應用效能產生影響

2.使用range,request(範圍請求)請求更新內容的部分

4.3.2.2 檔案替換

還有一種增量更新方式就是檔案替換,只更新需要更新的模組,這種方式只更新需要渲染程序的資源,大部分情況下主程序的資源不用更改,所以下載的資源會比較小,更新較快,因為是線上熱更新,更新完成後不用重新啟動軟體,只需要重新整理頁面重新載入資源即可。其實之前我覺的這樣的思路挺好的,看下面的流程圖也是可以實現的,也很符合商家客服桌面應用產品需求。

64016.png

可是後來發現其實忽略了以下兩個點:

  • 替換使用者本地檔案這個本身有許可權問題,比如windows使用者安裝到了C盤,寫入檔案是有管理員許可權限制的;

  • 檔案被佔用問題,眾所周知,當資料夾中存在正在被佔用的檔案時,刪除會失敗。所以在覆蓋原檔案同時需要退出應用避免佔用,所以這個方式也不是很可靠。

5.遇到的問題

Electron 的硬體加速功能,在 win7 或者 Linux 系統上,容易出現黑屏或者卡死。

解決方案:判斷是不是win7及以下系統,如果是app.disableHardwareAcceleration (),禁用當前應用程式的硬體加速。

  • Uncaught ReferenceError: require is not defined,這個報錯是試圖在渲染程序使用node的時候出現的,不是不能用,只要開啟 主程序的nodeIntegration: true就好了, 但不建議,有安全問題。

解決方案:

64010.jpg

  • Note:you may have one or two (large) stale temporary file(s) left in your temporary directory (Generally this only happens on Windows 9x)這個是打包了半天都打不出來一個完整的包的情況下出現的。

解決方案:當時是因為我沒刪除原來的包導致我放打包檔案的C盤滿了。。。所以刪除一些快取就好了,nsis打包大概率都是跟磁碟有關。

  • 下載npm包特別慢

解決方案:yarn安裝;Electron相關的包優先使用淘寶映象安裝;使用公司映象安裝公司內部包。

6.總結

一路開發下來,感慨很多,作為公司第一個Electron應用,不管是在開發上,打包上,或者說在部署上,都遇到了一些挑戰,在網上也沒有比較詳細的文件,外面做的好的也不會把詳細方案分享出來,但是即使遇到了這些問題,也不能否認Electron是目前最適配於我們業務目標以及適配於開發資源的一個框架。目前已有線上穩定版本,逐步在推廣到全部商家客服。接下來需要完善的開發流程,克服的技術難點有很多,商家客服工作臺應用也會越來越完善。

文/Uni