作者:京東零售 朱鳴輝
基于 Taro 打造的京東鴻蒙 APP 已跟隨鴻蒙 Next 系統(tǒng)公測,本系列文章將深入解析 Taro 如何實(shí)現(xiàn)使用 React 開發(fā)高性能鴻蒙應(yīng)用的技術(shù)內(nèi)幕
背景
隨著鴻蒙操作系統(tǒng)的快速發(fā)展,開發(fā)者們期待將現(xiàn)有跨平臺應(yīng)用遷移到鴻蒙平臺。Taro作為一個(gè)流行的跨平臺開發(fā)框架,其支持鴻蒙系統(tǒng)的可能性引起了廣泛關(guān)注。
然而,鴻蒙系統(tǒng)采用全新的ArkUI框架作為原生UI開發(fā)方案,與Taro原本支持的平臺存在顯著差異。將Taro的React開發(fā)模式與ArkUI的聲明式UI開發(fā)范式進(jìn)行有效對接成為了一個(gè)技術(shù)難題。
本文將探討Taro框架如何通過創(chuàng)新方案實(shí)現(xiàn)React代碼在ArkUI上的運(yùn)行。我們將解析Taro的運(yùn)行時(shí)原理,剖析其如何將React組件轉(zhuǎn)換為ArkUI可識別的結(jié)構(gòu),以及相關(guān)技術(shù)挑戰(zhàn)和解決方案。
Taro運(yùn)行時(shí)原理介紹
為了理解Taro適配ArkUI的核心機(jī)制,我們首先需要深入了解Taro的運(yùn)行時(shí)原理。Taro通過巧妙的設(shè)計(jì),將React代碼轉(zhuǎn)換為各平臺可執(zhí)行的形式,其中包括對鴻蒙平臺的適配。下面將詳細(xì)介紹 Taro 是如何將 React 代碼轉(zhuǎn)換為ArkUI可執(zhí)行的形式,以及節(jié)點(diǎn)轉(zhuǎn)換的流程細(xì)節(jié)。
1. 從 React 到 Taro
React 跨平臺的秘訣
在 Taro 的運(yùn)行時(shí)中,首先執(zhí)行的是開發(fā)者編寫的 React 業(yè)務(wù)代碼。這些代碼定義了業(yè)務(wù)應(yīng)用的結(jié)構(gòu)、邏輯和狀態(tài)管理。那么既然要對接React,那肯定先得了解它的核心架構(gòu),React是怎么運(yùn)作的:
?
了解了React的基本架構(gòu)后,我們可以清晰地看到,Renderer 作為渲染器,負(fù)責(zé)將React的虛擬節(jié)點(diǎn)操作最終映射到相應(yīng)的平臺上。例如,react-dom將這些操作對接到瀏覽器上,而react-native則將其對接到iOS或Android平臺。這種設(shè)計(jì)使得React能夠適配不同的運(yùn)行環(huán)境。
正是基于這種思路,Taro 團(tuán)隊(duì)設(shè)計(jì)了 Taro Renderer。這個(gè)渲染器充當(dāng)了 React 與 Taro 虛擬節(jié)點(diǎn)樹之間的橋梁,使得 React 的操作可以被轉(zhuǎn)換為 Taro 的中間表示。
通過實(shí)現(xiàn) Taro Renderer 生成 Taro 虛擬節(jié)點(diǎn)樹
HostConfig接口實(shí)現(xiàn)
?
要實(shí)現(xiàn) Taro 的 Renderer,我們需要實(shí)現(xiàn) React Reconciler 所需的 hostConfig 接口。這個(gè)接口定義了一系列方法,用于創(chuàng)建、更新和管理渲染目標(biāo)平臺的元素。以下是一些關(guān)鍵的 hostConfig 方法:
?createElement:創(chuàng)建ArkUI對應(yīng)的元素。
?createTextInstance:創(chuàng)建文本節(jié)點(diǎn)。
?appendChild:將子元素添加到父元素。
?removeChild:從父元素中移除子元素。
?insertBefore:在指定位置插入元素。
?commitUpdate:更新元素屬性。
通過實(shí)現(xiàn)這些方法,Taro Renderer 能夠?qū)?strong> React 的操作轉(zhuǎn)換為 Taro 虛擬節(jié)點(diǎn)樹的相應(yīng)操作。這個(gè)虛擬節(jié)點(diǎn)樹是 Taro 實(shí)現(xiàn)跨平臺的核心,它為不同平臺的渲染提供了統(tǒng)一的中間表示。
// 部分HostConfig接口實(shí)現(xiàn)的代碼 const hostConfig: HostConfig { // 創(chuàng)建Taro虛擬節(jié)點(diǎn) createInstance (type, props: Props, _rootContainerInstance, _hostContext, internalInstanceHandle: Fiber) { const element: TaroElement = TaroNativeModule.createTaroNode(type) precacheFiberNode(internalInstanceHandle, element) updateFiberProps(element, props) return element }, // 更新屬性 commitUpdate (dom, updatePayload, _, oldProps, newProps) { updatePropsByPayload(dom, oldProps, updatePayload) updateFiberProps(dom, newProps) }, // 插入節(jié)點(diǎn) insertBefore (parent: TaroElement, child: TaroElement, refChild: TaroElement) { parent.insertBefore(child, refChild) }, // 移除節(jié)點(diǎn) removeChild (parent: TaroElement, child TaroElement) { parent.removeChild(child) }, // ... }
2. 從 Taro 到 ArkUI
在將 Taro 虛擬節(jié)點(diǎn)樹轉(zhuǎn)換為 ArkUI 的過程中,我們需要進(jìn)行幾個(gè)關(guān)鍵步驟:
?
Taro Element轉(zhuǎn)換 ArkUI過程
首先,我們需要在 ArkUI 層面實(shí)現(xiàn)一套與 Taro 組件對應(yīng)的組件庫。這個(gè)步驟至關(guān)重要,因?yàn)樗⒘?Taro 組件和 ArkUI 組件之間的映射關(guān)系。例如,我們需要為 Taro 的 View、Text、Image 等基礎(chǔ)組件創(chuàng)建對應(yīng)的 ArkUI 組件。這樣,當(dāng)我們遍歷 Taro 虛擬節(jié)點(diǎn)樹時(shí),就能找到每個(gè)節(jié)點(diǎn)在 ArkUI 中的對應(yīng)實(shí)現(xiàn)。
?
在節(jié)點(diǎn)映射的過程中,我們注意到 Taro 虛擬節(jié)點(diǎn)樹與實(shí)際 ArkUI 視圖結(jié)構(gòu)存在差異。這些差異主要體現(xiàn)在以下幾個(gè)方面:
?復(fù)合組件結(jié)構(gòu):某些 Taro 組件在 ArkUI 中可能需要多個(gè)組件配合實(shí)現(xiàn)。例如,ScrollView 組件在 ArkUI 中可能需要一個(gè) Scroll 節(jié)點(diǎn)搭配一個(gè) Stack 來實(shí)現(xiàn)完整功能。
?層級位置調(diào)整:一些特殊定位的節(jié)點(diǎn)(如 Fixed 定位的元素)在最終渲染時(shí)的位置可能與其在虛擬節(jié)點(diǎn)樹中的層級不一致。這需要在生成渲染樹時(shí)進(jìn)行特殊處理。
?平臺特定組件:某些 Taro 組件可能需要使用 ArkUI 特有的組件或布局方式來實(shí)現(xiàn),這要求我們在轉(zhuǎn)換過程中進(jìn)行適當(dāng)?shù)恼{(diào)整和映射。
因此,在生成渲染樹時(shí),我們需要一個(gè)更復(fù)雜的轉(zhuǎn)換過程,不僅要考慮簡單的一對一映射,還要處理這些結(jié)構(gòu)性的差異,確保最終生成的 ArkUI 組件樹能夠正確反映預(yù)期的視圖結(jié)構(gòu)和布局。因此,在Taro > ArkUI的節(jié)點(diǎn)對接中,我們需要維護(hù)一棵 Render Tree,用于做中間的橋梁。
?
1. 根據(jù)組件類型 創(chuàng)建 Taro Element
在創(chuàng)建 Taro Element 的過程中,我們根據(jù)組件的類型來實(shí)例化相應(yīng)的 Taro 元素。這一步驟是將 React 組件轉(zhuǎn)換為 Taro 內(nèi)部表示的關(guān)鍵。
// 根據(jù)組件類型創(chuàng)建對應(yīng)的Taro節(jié)點(diǎn) std::shared_ptr TaroDocument::CreateElement(napi_value &node) { // 獲取組件類型 TAG_NAME tag_name_ = TaroDOM::TaroElement::GetTagName(node); // 根據(jù)組件類型,創(chuàng)建對應(yīng)的實(shí)例 std::shared_ptr item; switch (tag_name_) { case TAG_NAME::SCROLL_VIEW: { item = std::make_shared(node); break; } case TAG_NAME::IMAGE: item = std::make_shared(node); break; } case TAG_NAME::SPAN: case TAG_NAME::TEXT: { item = std::make_shared(node); break; } case TAG_NAME::SWIPER: { item = std::make_shared(node); break; } // ... } return item; }
2. Taro Element 創(chuàng)建 Taro RenderNode
在創(chuàng)建完 Taro Element 之后,下一步是將其轉(zhuǎn)換為 Taro RenderNode。這個(gè)過程是將 Taro 的內(nèi)部表示進(jìn)一步轉(zhuǎn)化為更接近 ArkUI 結(jié)構(gòu)的渲染節(jié)點(diǎn)。
// 創(chuàng)建 Taro RenderNode void TaroSwiper::Build() { if (!is_init_) { // create render node TaroElementRef element = std::static_pointer_cast(shared_from_this()); auto render_swiper = std::make_shared(element); render_swiper->Build(); } }
3. Taro RenderNode 創(chuàng)建 ArkUI Node
最后一步是將 Taro RenderNode 轉(zhuǎn)換為實(shí)際的 ArkUI 節(jié)點(diǎn)。這個(gè)過程涉及到直接與 ArkUI 的底層 API 交互,創(chuàng)建和配置 ArkUI 的原生節(jié)點(diǎn)。實(shí)現(xiàn)了從 Taro 的渲染節(jié)點(diǎn)到 ArkUI 實(shí)際可渲染節(jié)點(diǎn)的最終轉(zhuǎn)換。
// 創(chuàng)建 ArkUI Node void TaroSwiperNode::Build() { NativeNodeApi *nativeNodeApi = NativeNodeApi::getInstance(); // 創(chuàng)建一個(gè)Swiper的ArkUI節(jié)點(diǎn) SetArkUINodeHandle(nativeNodeApi->createNode(ARKUI_NODE_SWIPER)); }
通過這三個(gè)步驟,我們在 C++ 層面成功實(shí)現(xiàn)了 React 組件結(jié)構(gòu)到 ArkUI 原生組件結(jié)構(gòu)的映射。這一過程使 Taro 應(yīng)用能夠在鴻蒙系統(tǒng)上準(zhǔn)確地渲染和運(yùn)行,為跨平臺開發(fā)提供了有力支持。
總結(jié)
最后總結(jié)下,本文探討了Taro框架如何將React代碼成功運(yùn)行在鴻蒙系統(tǒng)的ArkUI上。這個(gè)過程主要分為兩個(gè)關(guān)鍵部分:
React > ArkUI 架構(gòu)圖
1. Taro對接React
Taro通過實(shí)現(xiàn)自定義的Renderer來對接React。這個(gè)Renderer包含了一系列方法,如createInstance、commitUpdate等,用于將React的操作轉(zhuǎn)換為Taro虛擬節(jié)點(diǎn)樹的操作。這個(gè)虛擬節(jié)點(diǎn)樹是Taro實(shí)現(xiàn)跨平臺的核心,為不同平臺的渲染提供了統(tǒng)一的中間表示。
2. Taro對接ArkUI
Taro通過自定義Renderer將React操作轉(zhuǎn)換為虛擬節(jié)點(diǎn)樹,然后通過三步轉(zhuǎn)換過程將其映射到ArkUI結(jié)構(gòu)。這個(gè)過程涉及Taro Element、Taro RenderNode和ArkUI Node這三棵樹的維護(hù),主要通過這三個(gè)流程步驟實(shí)現(xiàn):
1.創(chuàng)建Taro Element:這一步將React組件轉(zhuǎn)換為Taro內(nèi)部表示。
2.創(chuàng)建Taro RenderNode:將Taro的內(nèi)部表示進(jìn)一步轉(zhuǎn)化為更接近ArkUI層級結(jié)構(gòu)的渲染節(jié)點(diǎn)。
3.創(chuàng)建ArkUI Node:最后一步是將Taro RenderNode轉(zhuǎn)換為實(shí)際的ArkUI節(jié)點(diǎn),直接與ArkUI的底層API交互。
通過這種方式,Taro成功地將React組件結(jié)構(gòu)映射到ArkUI原生組件結(jié)構(gòu),使得Taro應(yīng)用能夠在鴻蒙系統(tǒng)上準(zhǔn)確地渲染和運(yùn)行,同時(shí)也為跨平臺開發(fā)提供了有力支持。
?
系列往期精選:
?《京東鴻蒙上線前瞻——使用 Taro 打造高性能原生應(yīng)用》?
-
操作系統(tǒng)
+關(guān)注
關(guān)注
37文章
6620瀏覽量
123044 -
APP
+關(guān)注
關(guān)注
33文章
1563瀏覽量
72275 -
代碼
+關(guān)注
關(guān)注
30文章
4700瀏覽量
68107
發(fā)布評論請先 登錄
相關(guān)推薦
評論