跨平台React Native鸿蒙开发案例十:使用TuboModule的demo
这是一个基于华为鸿蒙系统与React Native深度集成的混合应用架构,主要实现了多表面应用组件管理。摘要如下: 架构核心:通过MultiSurface组件管理多个React Native渲染表面,实现原生与JS环境的高度融合。 关键技术点: 使用RNInstance管理JS运行环境 通过RNSurface实现虚拟DOM到原生UI的转换 集成SampleTurboModulePackage提供原
这是一个基于华为鸿蒙操作系统(OpenHarmony)与React Native深度集成的多表面应用组件架构。这段代码构建了一个复杂的混合应用入口,展示了在现代跨平台移动应用开发中如何实现原生组件与JavaScript运行环境的高度融合。
从技术架构的宏观层面分析,这段代码实现了一个名为MultiSurface的多表面应用组件,它作为应用的入口点,负责管理和协调多个React Native表面的显示和交互。代码结构分为多个逻辑层次:模块导入、构建器函数定义、包管理、组件装饰、生命周期管理和UI构建等。
在模块导入部分,代码引入了多个核心组件和接口。RNInstance代表React Native运行实例,负责管理JavaScript运行环境。RNOHCoreContext提供核心上下文信息,包含应用配置、资源管理等重要功能。ResourceJSBundleProvider负责加载和管理JavaScript bundle资源文件。RNSurface是React Native在鸿蒙平台上的渲染表面,负责将虚拟DOM转换为原生UI组件。
说明
这是一个使用TuboModule的demo工程。
目录结构
SampleProject – RN侧工程
SampleApp – 原生工程
环境搭建
- 在
SampleProject/MainProject目录下执行 npm i @react-native-oh/react-native-harmony@x.x.x或yarn add @react-native-oh/react-native-harmony@x.x.x 安装依赖,执行 npm run dev 生成 bundle; - 在
entry目录下执行 ohpm i @rnoh/react-native-openharmony@x.x.x 安装依赖; - 检查
SampleApp、entry目录下是否生成oh-modules文件夹; - 用 DevEco Studio 打开
SampleApp,执行 Sync and Refresh Project; - 点击 File > Project Structure > Signing Configs,登录并完成签名;
- 点击右上角的 run 启动项目。
效果预览
启动后页面效果如下:

RNComponentContext和RNOHContext分别提供组件级别和应用级别的上下文管理。buildRNComponentForTag用于构建特定标签的RN组件。RNPackageContext和RNPackage提供RN包管理的相关功能。ComponentBuilderContext是组件构建器的上下文环境。
特别值得注意的是SampleTurboModulePackage的导入,这是一个自定义的Turbo模块包,用于提供高性能的原生功能扩展。这种设计体现了模块化架构的思想,允许开发者根据业务需求灵活扩展功能模块。
@Builder装饰器用于定义buildCustomComponent函数,这是一个自定义组件构建器。虽然当前实现为空栈,但提供了扩展自定义原生组件的能力。这种设计模式在复杂应用中非常常见,为后续的功能扩展预留了接口。
wrappedCustomRNComponentBuilder通过wrapBuilder函数对构建器进行包装,增强了组件的功能性和扩展性。这种包装器模式可以增强组件的功能而不改变其核心结构。
createRNPackages函数定义了RN包的创建逻辑,返回一个包含SampleTurboModulePackage实例的数组。这种设计允许应用集成多个功能包,每个包都可以提供特定的业务功能或系统服务。
@Entry装饰器标识这个组件是应用的入口点,@Component装饰器声明这是一个自定义组件结构。组件命名为MultiSurface,明确表达了其支持多表面渲染的技术特性。
在状态管理方面,代码使用了鸿蒙的响应式状态系统。@StorageLink(‘RNOHCoreContext’)创建了一个与AppStorage双向绑定的rnohCoreContext属性。这种机制确保了应用状态的全局一致性管理,当全局状态发生变化时,所有相关的组件都会自动更新。
private instance管理React Native运行实例。private bundlePath指定JavaScript bundle文件的路径。private moduleName定义模块名称。@State isBundleReady是一个响应式状态变量,用于控制UI的渲染时机。
aboutToAppear是一个异步生命周期函数,在组件即将显示时执行。函数内部首先输出日志信息,然后进行上下文有效性检查,确保运行环境准备就绪。
通过createAndRegisterRNInstance方法创建并注册React Native实例,该方法接受一个配置对象,包含多个重要参数:createRNPackages函数用于创建RN包集合,enableNDKTextMeasuring启用原生文本测量功能,enableBackgroundExecutor控制后台执行器,enableCAPIArchitecture启用新的架构特性,arkTsComponentNames定义ArkTS组件名称列表。
RNComponentContext的创建过程涉及多个层次:从核心上下文创建RNOHContext,包装自定义组件构建器,包装标准RN组件构建器,以及创建新的映射表。这种层次化的上下文管理确保了组件运行环境的完整性和一致性。
runJSBundle方法异步执行JavaScript bundle的加载和运行过程。ResourceJSBundleProvider通过资源管理器获取指定的bundle文件。当bundle加载完成后,通过Promise的then方法将isBundleReady状态设置为true,并输出加载完成日志信息。
MultiSurfaceItem是一个组件级别的构建器函数,用于创建多表面项。它接收moduleName和instance作为参数,在Column容器中渲染RNSurface组件。surfaceConfig配置对象设置appKey属性,ctx参数创建新的组件上下文环境。
在build方法中,使用NavDestination组件作为导航目标容器,内部使用Column进行垂直布局。只有当isBundleReady为true时,才会渲染实际的RN组件内容,这种条件渲染机制避免了在资源未准备好时显示不完整的界面。
- 点击【•调用TurboModule回调方法】按钮,会有返回结果(… from native side)回填到按钮;
- 点击【•调用TurboModule异步方法】按钮,会有返回结果(rejected on native side)回填到按钮;
- 点击【•调用原生console.log方法】按钮,会在DevEco控制台打印日志(在Native中打印日志);
- 点击【•调用TurboModule2的test方法】按钮,手机界面上会有一个alert弹框,提示“调用 SampleTurboModule2 的 Test”;
- 点击【•调用TurboModule2的getObject方法】按钮,手机界面上会有一个alert弹框,提示“{ “x”: 100 }”;
- 点击【•调用TurboModule2的getRequest方法】按钮,手机界面上会有一个alert弹框,里面打印网络请求返回的内容;
- 点击【•调用TurboModule2的eatFruit方法】按钮,手机界面上会有一个alert弹框,提示“正在吃水果,大菠萝很好吃。颜色呢?透明的”;
- 点击【•调用TurboModule2的checkPwd方法】按钮,手机界面上会有一个alert弹框,提示“checkPwd success!”;
- 点击【•调用WorkerTurboModule回调方法:】按钮,会有返回结果(… from native worker side)回填到按钮;
- 点击【•调用WorkerTurboModule异步回调方法:】按钮,会有返回结果(rejected on native worker side)回填到按钮;
- 点击【•在worker线程中调用原生console.log方法:】按钮,会在DevEco控制台打印日志(在Native的worker线程中打印日志)。
import {
RNInstance,
RNOHCoreContext,
ResourceJSBundleProvider,
RNSurface,
RNComponentContext,
RNOHContext,
buildRNComponentForTag,
RNPackageContext,
RNPackage,
ComponentBuilderContext
} from '@rnoh/react-native-openharmony';
import { SampleTurboModulePackage } from '../TurboModule/SampleTurboModulePackage';
@Builder
export function buildCustomComponent(ctx: ComponentBuilderContext) {
Stack() {
}.position({ x: 0, y: 0 })
}
const wrappedCustomRNComponentBuilder = wrapBuilder(buildCustomComponent);
export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
return [
new SampleTurboModulePackage(ctx),
];
}
@Entry
@Component
export struct MultiSurface {
@StorageLink('RNOHCoreContext') rnohCoreContext: RNOHCoreContext | undefined = undefined;
private instance: RNInstance | undefined;
private bundlePath = 'bundle.harmony.js';
private moduleName = 'App';
@State isBundleReady: boolean = false;
async aboutToAppear() {
console.log("MultiSurface=====")
if (!this.rnohCoreContext) {
return;
}
this.instance = await this.rnohCoreContext.createAndRegisterRNInstance({
createRNPackages: createRNPackages,
enableNDKTextMeasuring: true,
enableBackgroundExecutor: false,
enableCAPIArchitecture: true,
arkTsComponentNames: []
});
const ctxInstance: RNComponentContext = new RNComponentContext(
RNOHContext.fromCoreContext(this.rnohCoreContext!, this.instance),
wrapBuilder(buildCustomComponent),
wrapBuilder(buildRNComponentForTag),
new Map()
);
// await this.instance.runJSBundle(
// new ResourceJSBundleProvider(
// getContext().resourceManager,
// 'bundle/basic/basic.harmony.bundle'
// )
// );
await this.instance.runJSBundle(
new ResourceJSBundleProvider(
getContext().resourceManager,
this.bundlePath
)).then(() => {
this.isBundleReady = true;
console.log('instance 加载完成' + this.bundlePath);
})
}
@Builder
MultiSurfaceItem(moduleName: string, instance: RNInstance) {
Column() {
RNSurface({
surfaceConfig: {
appKey: moduleName,
},
ctx: new RNComponentContext(
RNOHContext.fromCoreContext(this.rnohCoreContext!, instance),
wrappedCustomRNComponentBuilder,
wrapBuilder(buildRNComponentForTag),
new Map()
),
})
}
.align(Alignment.Top)
.width('100%')
}
build() {
NavDestination() {
Column() {
if (this.isBundleReady) {
this.MultiSurfaceItem(this.moduleName, this.instance!)
}
}
.width('100%')
.height('100%')
}
}
}
更多推荐



所有评论(0)