React Native跨平台鸿蒙开发高级应用原理:OpenHarmony使用ContentSlot占位组件管理Native API创建的组件
在开发涉及原生模块(Native API)与前端框架(如React, Vue等)集成的Web应用时,经常需要使用到ContentSlot或Placeholder组件来管理原生组件的占位。此外XComponent的libraryname参数不支持跨module使用,即无法找到其它模块中的同名so,RNOH的日志会提示找不到对应的so。因此,RNOH将使用ContentSlot作为占位组件。的介绍,先
命令式组件
ContentSlot接入
根据OpenHarmony关于XComponentType的介绍,先前在RNOH中使用的用于Native UI节点的占位容器XComponent的NODE类型不再演进,推荐使用ContentSlot占位组件管理Native API创建的组件,ContentSlot在内存和性能方面都优于NODE类型的XComponent。此外XComponent的libraryname参数不支持跨module使用,即无法找到其它模块中的同名so,RNOH的日志会提示找不到对应的so。因此,RNOH将使用ContentSlot作为占位组件。以下是使用ContentSlot接入的流程介绍:

CAPI版本使用 ContentSlot 总共分成了2个步骤:
createSurface的时候创建ArkUISurface;startSurface的时候将 CPP 的ArkUISurface连接到ArkUI的NodeContent上。
createSurface的时候主要做了以下的操作:
-
创建并将
ArkUISurface记录到Map中:void RNInstanceCAPI::createSurface( facebook::react::Tag surfaceId, std::string const& moduleName) { m_surfaceById.emplace( surfaceId, ArkUISurface( ··· surfaceId, moduleName)); } -
在
ArkUISurface中创建nodeContentHandle与rootView,通过attachToNodeContent来链接nodeContentHandle与rootView,用于挂载 C-API组件,并在Surface上统一处理 Touch 事件:ArkUISurface::ArkUISurface( ... SurfaceId surfaceId, int rnInstanceId, std::string const& appKey) : m_surfaceId(surfaceId), m_scheduler(std::move(scheduler)), m_componentInstanceRegistry(std::move(componentInstanceRegistry)), m_surfaceHandler(SurfaceHandler(appKey, surfaceId)) { m_scheduler->registerSurface(m_surfaceHandler); m_taskExecutor = taskExecutor; m_rootView = componentInstanceFactory->create( surfaceId, facebook::react::RootShadowNode::Handle(), "RootView"); if (m_rootView == nullptr) { LOG(ERROR) << "Couldn't create rootInstanceComponent for surface with id: " << surfaceId; return; } ... } void ArkUISurface::attachToNodeContent(NodeContentHandle nodeContentHandle) { m_threadGuard.assertThread(); if (m_nodeContentHandle.has_value()) { throw RNOHError( "ArkUISurface: calling attachToNodeContent on an already attached Surface"); } m_nodeContentHandle = nodeContentHandle; m_nodeContentHandle.value().addNode(m_rootView->getLocalRootArkUINode()); HarmonyReactMarker::logMarker( HarmonyReactMarker::HarmonyReactMarkerId::CONTENT_APPEARED, m_rootView->getTag()); }
startSurface 的时候主要做了以下的操作:
-
在 ArkTS 侧创建
ContentSlot,并在ContentSlot中传入rootViewNodeContent,rootViewNodeContent为新建的NodeContent组件:// RNSurface.ets private rootViewNodeContent: NodeContent = new NodeContent(); ... ... ... if (this.ctx.rnInstance.getArchitecture() === "C_API") { ContentSlot(this.rootViewNodeContent) } -
调用
RNOHAppNapiBridge.cpp中的attachRootView,将rootView添加到ArkTS侧的NodeContent上:static napi_value attachRootView(napi_env env, napi_callback_info info) { return invoke(env, [&] { ArkJS arkJS(env); auto args = arkJS.getCallbackArgs(info, 3); auto instanceId = arkJS.getInteger(args[0]); auto surfaceId = arkJS.getInteger(args[1]); auto nodeContentHandle = NodeContentHandle::fromNapiValue(env, args[2]); auto rnInstance = maybeGetInstanceById(instanceId); if (!rnInstance) { return arkJS.createFromRNOHError( RNOHError("Failed to get the RNInstance")); } auto rnInstanceCAPIRawPtr = std::dynamic_pointer_cast<RNInstanceCAPI>(rnInstance); if (rnInstanceCAPIRawPtr != nullptr) { rnInstanceCAPIRawPtr->attachRootView( std::move(nodeContentHandle), surfaceId); } return arkJS.getNull(); }); } -
将 rootView 连接到
ContentSlot后,rootView 就作为 CAPI 组件的根节点,后续的子孙节点通过 Mutation 指令逐个插入到组件树上。
在开发涉及原生模块(Native API)与前端框架(如React, Vue等)集成的Web应用时,经常需要使用到ContentSlot或Placeholder组件来管理原生组件的占位。这种需求尤其在微前端架构、渐进式Web应用(PWA)或跨平台应用中非常常见。下面将介绍如何在几种不同的前端框架中实现ContentSlot或Placeholder组件来管理原生组件的创建和展示。

欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。
更多推荐
所有评论(0)