这是一个基于华为鸿蒙操作系统(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 – 原生工程

环境搭建

  1. SampleProject/MainProject 目录下执行 npm i @react-native-oh/react-native-harmony@x.x.xyarn add @react-native-oh/react-native-harmony@x.x.x 安装依赖,执行 npm run dev 生成 bundle;
  2. entry 目录下执行 ohpm i @rnoh/react-native-openharmony@x.x.x 安装依赖;
  3. 检查 SampleAppentry 目录下是否生成 oh-modules 文件夹;
  4. 用 DevEco Studio 打开 SampleApp,执行 Sync and Refresh Project
  5. 点击 File > Project Structure > Signing Configs,登录并完成签名;
  6. 点击右上角的 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组件内容,这种条件渲染机制避免了在资源未准备好时显示不完整的界面。

  1. 点击【•调用TurboModule回调方法】按钮,会有返回结果(… from native side)回填到按钮;
  2. 点击【•调用TurboModule异步方法】按钮,会有返回结果(rejected on native side)回填到按钮;
  3. 点击【•调用原生console.log方法】按钮,会在DevEco控制台打印日志(在Native中打印日志);
  4. 点击【•调用TurboModule2的test方法】按钮,手机界面上会有一个alert弹框,提示“调用 SampleTurboModule2 的 Test”;
  5. 点击【•调用TurboModule2的getObject方法】按钮,手机界面上会有一个alert弹框,提示“{ “x”: 100 }”;
  6. 点击【•调用TurboModule2的getRequest方法】按钮,手机界面上会有一个alert弹框,里面打印网络请求返回的内容;
  7. 点击【•调用TurboModule2的eatFruit方法】按钮,手机界面上会有一个alert弹框,提示“正在吃水果,大菠萝很好吃。颜色呢?透明的”;
  8. 点击【•调用TurboModule2的checkPwd方法】按钮,手机界面上会有一个alert弹框,提示“checkPwd success!”;
  9. 点击【•调用WorkerTurboModule回调方法:】按钮,会有返回结果(… from native worker side)回填到按钮;
  10. 点击【•调用WorkerTurboModule异步回调方法:】按钮,会有返回结果(rejected on native worker side)回填到按钮;
  11. 点击【•在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%')
    }
  }
}
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐