富文字及編輯器的跨平臺方案

vivo網際網路技術發表於2021-08-17

一、前言

之前在《富文字編輯器之遊戲角色升級 ing》一文中,跟大家分享了富文字編輯器的發展歷程、選型技巧和擴充套件方案。今天將和大家一起聊一聊“富文字及編輯器跨平臺方案”那些事。

大家應該注意到了,標題用的是“富文字及編輯器”,而非“富文字編輯器”。也就意味著本文將圍繞富文字跨平臺和編輯器跨平臺兩大部分進行介紹。

通過跨平臺方案的分享,希望能給有富文字編輯器跨平臺相關需求的小夥伴帶來一些幫助。

二、為什麼要跨平臺

對於一個產品來說,使用者的需求程度在一定程度上反映了其產品的價值。對於富文字編輯器而言,以 WEB 端(PC 瀏覽器、移動瀏覽器)、移動端(IOS 應用、Android 應用)、桌面端(windows、macOS)各自為戰的系統生態,已經無法滿足使用者的需求。同時對於研發人員而言,各端都需要大量的資源投入進行重複能力的開發,這無疑是一種資源的消耗。因此越來越多的團隊開始尋求突破,建立跨平臺的編輯生態,在不同的平臺、不同的終端上實現資料互通,展現體驗一致的編輯能力。

(圖片來源於網路)

上面是比較籠統的概念,舉例子說明下:

社交型別的應用

以微博中的場景為例:假如你用電腦網頁版微博釋出了一篇長文,然後分享給了你的朋友,期間發現內容可能需要編輯下。這個時候問題來了,你是傾向於放下手機開啟電腦編輯,還是直接切到手機微博來編輯。我猜絕大多數小夥伴應該會選擇用手機微博進行編輯,那麼我們就可以發現在這個過程中經歷了 Web 端發表--微信小程式檢視--APP 端編輯幾個階段,這其中的流轉其實就是跨平臺操作。

記錄型別的應用

以手機端便籤應用為例:越來越多的使用者習慣用便籤之類的應用記錄一些生活事項,那這些記錄是僅儲存在本地裝置中的嗎?NO! 如果僅儲存在本地,那麼換臺手機或者清除資料後,資料就無法找回了,這必然不符合大眾的需求。大部分記錄類應用的資料是儲存在雲端的,使用雲端儲存既能滿足跨裝置的資料遷移,同時帶來了跨平臺可瀏覽、可編輯、可刪除的附加價值。

以上,簡單介紹了富文字編輯器跨平臺的兩個應用場景,可以看出富文字編輯器跨平臺已經成為一種必然的需要。既然已經清晰了為什麼要跨平臺,下一步我們就來探討下如何實現跨平臺。

三、富文字跨平臺

富文字,在這裡指代“編輯器所輸出的資料”。富文字的跨平臺,實質上就是使富文字在不同平臺內以其原生的方式展示相同的效果。

注:在本章節中探討的場景主要是 WEB 端的富文字 HTML 如何可以在 Android、小程式中展示原生的效果。

有朋友也許會問,HTML 在 Android 內可以用 HTML.fromHtml 方法解析展示富文字內容。微信小程式也可以用 rich-text 富文字元件直接渲染,既然用 HTML 就可以跨平臺展示,為什麼還要單獨拆分一個章節探討呢?對於這個問題,首先給大家分別展示下用 HTML 資料渲染在不同平臺中可能出現的問題:

從上圖中可以看出,HTML的優點是特性豐富,靈活多變。而正因如此,其很難嚴格的定義資料。因此若是將HTML作為流轉的資料,很容易在不同平臺內出現解析相容問題。

那麼要在不同平臺間實現一致的展示效果,有兩種方案作為參考:

  • 方案一:將 HTML 強制轉化為各平臺都能正常適配的層級結構。

  • 方案二:利用一種通用的可供各端解析的資料模型,各端用原生元件解析渲染。

方案一雖然可以通過列舉不相容的場景正則替換,將源資料轉化為各平臺均可以正常解析的 HTML,但是從可擴充套件性的角度上來說,列舉替換的方案不太現實。既然如此,那就一起看看如何通過方案二實現。

通用的資料模型

考慮到 HTML 轉化中存在的問題,那麼通用的資料模型需要滿足以下條件:

  • 描述文件層級結構

  • 嚴格定義巢狀規則

  • 制定資料過濾機制

下圖分別對比了使用 JSON、XML 作為資料模型的優缺點,可以根據專案需要酌情選擇:

之前分享的文章中,L2 階段的富文字編輯器的資料模型多是 JSON 結構,本節直接沿用之前的例子展開介紹下 JSON 資料模型是如何滿足以上三個條件的:

遵循條件規範,定義好資料模型後,此時資料在各平臺間的流轉過程就如下圖所示:

整個流程總結下來就是:以通用資料模型作為媒介,打通 WEB 端與 Android、小程式的資料互通,在各平臺用原生的元件渲染頁面,最終實現富文字的跨平臺。

本節解決的問題是:WEB 端產出的富文字內容,在各平臺如何得到最本源的展示效果。那麼如何保證各個平臺都是輸出相同的資料模型呢?這也就引入了下節的內容——編輯器的跨平臺。

四、編輯器跨平臺

編輯器跨平臺,是指由各平臺提供功能模組,WEB 端提供排版編輯能力,最終執行在平臺特定的瀏覽器環境中。本節將以 Android App 的編輯器實現為例進行展開,其他平臺的編輯器實現原理相同。

以便籤 APP 為例,富文字內容編輯模組執行在由Native App 提供的 Webview 環境中,其工具欄選單、狀態顯示部分則由 Native App 原生控制元件組成。

為什麼不選擇直接用 Native 編輯器或者 Web 編輯器,而是選擇這樣組合的形式呢?

首先,如果選擇單一的編輯器或多或少存在一些問題,比如說:

  • Native 編輯器實現複雜富文字結構的開發成本較高,需要定製很多功能模組;

  • Web 編輯器在 Native APP 中操作能力有限,且互動體驗不及 Native 原生控制元件。

那麼兩者“取其精華”,選擇保留 Web 端富文字豐富靈活的排版能力,同時用 Native 原生控制元件關聯使用者操作,最終實現 1+1>2 的效果。具體體現在:

  • 靈活展示豐富的富文字內容;

  • 不同平臺的核心編輯程式碼可複用,降低跨平臺編輯器的開發成本;

  • 具備系統級控制許可權,極大地擴充套件了編輯器的能力組成(語音、圖片編輯等);

4.1 如何實現一個跨平臺的編輯器?

跨平臺編輯器重點需要解決的問題有兩點:

Native App 與執行在 webview 中的編輯器如何資料通訊?

Native 工具欄如何跟隨游標位置呈現不同的狀態?

首先,介紹下跨平臺的編輯器,各模組之間是如何互動的。

  • 編輯器會開放一些介面如 setData、getData、execCommand,供 Native APP 呼叫,向編輯器內新增內容。

  • Native APP 也會向編輯器提供一些介面,如 viewLoad、requestMedia、updateBtnStatus。編輯器可以根據自身的狀態,通過這些介面向 APP 內傳遞一些資料或者訊號,使得 APP 內的各種控制元件狀態得到重新整理。

  • Web 編輯器僅與 Native APP 建立通訊,與服務端的資料互動交由 Native APP 完成。

下面,將介紹幾個跨平臺編輯器的核心場景實現,供大家參考。

4.1.1 頁面初始化

跨平臺編輯器的編輯頁由 Native APP 和 Webview 中的 Web Editor 組成,那麼意味著頁面的初始化需要兩個模組協同實現。

一般情況下 Native APP 中原生控制元件的渲染速度是要快於 Webview 的渲染,這裡可以在 Editor loaded 之後,呼叫 Native APP 提供的初始化方法,將 Native APP 從 Loading 狀態切換至完成態。

假設此時儲存有草稿,可以在頁面 Load 後,直接呼叫 Editor 暴露的 setData 方法,初始化編輯器資料。

4.1.2 資料通訊

在編輯過程中,必然存在 Native APP 與 編輯器的雙向通訊,就以簡單的插入表情為例,整個操作流程分為以下幾個步驟:

1、點選表情按鈕,從鍵盤狀態切換至表情選擇皮膚,此時都屬於 Native APP 內部操作流程。

2、當點選某個表情後,就需要 Native APP 主動與編輯器建立通訊,通知編輯器需要執行插入表情的操作。

3、編輯器接收到插入表情的指令後,插入 Native APP 流轉過來的表情資料,同時觸發了編輯器內部的狀態重新整理,比如說字數計算、歷史記錄的重新整理。

4、由於現在的撤銷、重做按鈕已經不在編輯器內部,當歷史記錄重新整理時,需要對按鈕的狀態進行重置。這個時候就需要編輯器呼叫 Native APP 提供的狀態重新整理方法,通知 Native APP 進行按鈕狀態的更新。

這樣就完成了兩個模組的雙向資料通訊。

4.1.3 媒體嵌入

媒體嵌入是富文字編輯器中必不可少的一部分,這裡單獨拿出來介紹,主要是因為跨平臺的富文字編輯器在上傳資源到服務端時,並不是常規的通過編輯器本身來實現的。那中間的處理邏輯是怎樣的呢?

Native APP 圖片選擇的流程就不過多贅述,直接進入到選擇之後上傳的部分。Native APP 選擇圖片之後,直接會呼叫服務端的介面將圖片上傳,與此同時還會攜帶選擇的圖片資訊(本地路徑、寬高資訊等等)傳遞給編輯器。

由於圖片上傳與圖片插入存在一定時間差,所以編輯器在最初接收到插入圖片的命令後,預設處理為 loading 狀態,等待 Native APP 上傳完成的訊號。

當服務端介面返回圖片載入完成的資訊後,Native APP 呼叫編輯器預先提供的介面,控制編輯器中某張圖片重新整理為完成時態。這樣就實現了資源的上傳及插入:

4.2 踩坑實踐瞭解一下!

當然,不是所有的事情都是一帆風順的。我在開發過程中,也踩了一些坑,跟大家分享下。

4.2.1 鍵盤的控制

預告:由於我使用的 Web 編輯器仍然依賴瀏覽器的 contenteditable 特性,所以下面的案例,並不具備普適性,大家僅供參考。

基於 contenteditable 的編輯器,在游標插入的時候,會自動喚起手機端的輸入法鍵盤。有些場景下,比如插入圖片後,預期鍵盤處於關閉狀態。但是在實際操作時,鍵盤會預設喚起,即系統鍵盤不受編輯器控制。

針對這種情況,我嘗試了一些解決方案,最終選擇採用雙管齊下的方式,增加雙重保險:

  • 在 Editor 插入操作執行前,增加禁用編輯和啟用編輯的切換,利用切換的時間差,將系統鍵盤的自動喚起機制失效。
editor.setAttribute('contenteditable', 'false')
setTimeout(() => {
  editor.setAttribute('contenteditable', 'true')
}, 150)
  • Native APP 提供控制鍵盤彈出、收起的方法,在 Editor 需要的時候呼叫系統能力實現控制自由。
JsBridge.call('updateKeyBoardState',
{ keyBoardState: true/false })JsBridge.call('updateKeyBoardState',{ keyBoardState: true/false })

4.2.2 資源的失敗重試

在編輯器中,資源上傳失敗均會配備重新上傳的機制。在跨平臺編輯器中,重新上傳需要在 WEB 編輯器中觸發,交由Native APP 重新上傳。Native APP上傳圖片的前提是拿到圖片的本地路徑。因此在前期設計時就需要重點關注以下幾個點:

  • Native APP 在呼叫編輯器插入圖片的介面時,就需要告知圖片對應的本地路徑,也作為後續狀態重新整理、失敗重試的參照條件。

  • 要增加本地路徑異常失效的處理(本地圖片刪除、移動等)。

讀到這裡,各位小夥伴對於如何實現一個跨平臺的富文字編輯器,是否已經胸有成竹了呢。本節只是探討了 Android APP 這一種平臺的場景,對於其他的平臺其實也是如此,比如桌面端平臺(Windows、Mac)的客戶端中,可以選擇用 CEF(Chromium Embedded FrameWork)提供瀏覽器環境。感興趣的小夥伴可以動手嘗試一下。

五、總結

本篇文章聚焦富文字跨平臺和編輯器跨平臺兩個角度,分析了為什麼要通過跨平臺的方案實現富文字 編輯器、以及如何實現兩類的跨平臺,其中重點介紹了跨平臺編輯器的核心流程和踩坑實踐。

到此,關於富文字編輯器的分享已經接近尾聲。通過這篇內容的介紹,希望大家在遇到諸如此類的需求時,可以觸類旁通,順順利利的將方案落地。

參考資料

1、rich-text |微信開放文件(opens new window)

2、有道雲筆記跨平臺富文字編輯器的技術演進

作者:vivo網際網路伺服器團隊-Tian Yuhan

相關文章