【ReactNative鸿蒙化-三方库使用与C-API集成】

目录

项目初始化

前置条件

初始化

[React Native 三方库使用与集成](#React Native 三方库使用与集成)

章节一:三方库的选择与集成

[1.1 识别适配包 (TPL)](#1.1 识别适配包 (TPL))

[1.2 安装核心依赖](#1.2 安装核心依赖)

章节二:业务页面与导航体系实现

[2.1 规范化开发:路由常量](#2.1 规范化开发:路由常量)

[2.2 嵌套导航实现逻辑](#2.2 嵌套导航实现逻辑)

[章节三:开启 C-API 高性能架构](#章节三:开启 C-API 高性能架构)

[3.1 核心配置步骤](#3.1 核心配置步骤)

章节四:原生模块底层桥接

[4.1 第一步:Native 依赖链接 (ohpm)](#4.1 第一步:Native 依赖链接 (ohpm))

[4.2 第二步:C++ 源码链接 (CMake)](#4.2 第二步:C++ 源码链接 (CMake))

[4.3 第三步:Codegen 自动生成胶水代码](#4.3 第三步:Codegen 自动生成胶水代码)

[4.4 第四步:原生包注册 (PackageProvider.cpp)](#4.4 第四步:原生包注册 (PackageProvider.cpp))

[4.5 第五步:ArkTS 工厂注册 (RNPackagesFactory.ets)](#4.5 第五步:ArkTS 工厂注册 (RNPackagesFactory.ets))

章节五:白名单与组件构建器

[5.1 ArkTS 组件白名单](#5.1 ArkTS 组件白名单)

[5.2 委托构建器](#5.2 委托构建器)

总结:集成全景图


项目初始化

前置条件

软件环境 DevEco Studio、VS Code、Node.js

初始化

  1. 初始化ReactNayive项目

    npx react-native@0.72.5 init RNNavigation --version 0.72.5

  2. 安装依赖

    npm i @react-native-oh/react-native-harmony@0.72.90

  3. 修改 package.json 文件

    {
    "name": "RNNavigation",
    "version": "0.0.1",
    "private": true,
    "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "lint": "eslint .",
    "start": "react-native start",
    "test": "jest",
    "harmony": "react-native bundle-harmony --dev" //需要添加的配置项
    },
    "dependencies": {
    "@react-native-oh/react-native-harmony": "^0.72.90", //此项会自动写入
    "react": "18.2.0",
    "react-native": "0.72.5"
    },
    "devDependencies": {
    "@babel/core": "^7.20.0",
    "@babel/preset-env": "^7.20.0",
    "@babel/runtime": "^7.20.0",
    "@react-native/eslint-config": "^0.72.2",
    "@react-native/metro-config": "^0.72.11",
    "@tsconfig/react-native": "^3.0.0",
    "@types/react": "^18.0.24",
    "@types/react-test-renderer": "^18.0.0",
    "babel-jest": "^29.2.1",
    "eslint": "^8.19.0",
    "jest": "^29.2.1",
    "metro-react-native-babel-preset": "0.76.8",
    "prettier": "^2.4.1",
    "react-test-renderer": "18.2.0",
    "typescript": "4.8.4"
    },
    "engines": {
    "node": ">=16"
    }
    }

  4. 创建harmony项目

  1. 安装rn harmony 依赖

    ohpm i @rnoh/react-native-openharmony@0.72.90

  1. 配置 Metro 打包器以支持 Harmony

    /**

    • @ProjectName : RNNavigation
    • @Author : GuoJiaHui
    • @Time : 2026年04月19日 10:00 AM
    • @Description : Metro bundler configuration
      */
      const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
      const {
      createHarmonyMetroConfig,
      } = require('@react-native-oh/react-native-harmony/metro.config');

    /**

    • Metro configuration for OpenHarmony
    • Integrates RNOH-specific resolver and transformer rules.
    • @type {import('metro-config').MetroConfig}
      */
      const config = {
      transformer: {
      getTransformOptions: async () => ({
      transform: {
      experimentalImportSupport: false,
      inlineRequires: true,
      },
      }),
      },
      };

    module.exports = mergeConfig(
    getDefaultConfig(__dirname),
    createHarmonyMetroConfig({
    reactNativeHarmonyPackageName: '@react-native-oh/react-native-harmony',
    }),
    config,
    );

  2. 初始化编译

    npm run harmony

  1. 修改Haymony工程

这里需要新建两个文件

复制代码
project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(OH_MODULE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../oh_modules")
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")

set(RNOH_CPP_DIR "${OH_MODULE_DIR}/@rnoh/react-native-openharmony/src/main/cpp")
set(RNOH_GENERATED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/generated")
set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments")
set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
add_compile_definitions(WITH_HITRACE_SYSTRACE)
set(WITH_HITRACE_SYSTRACE 1) # for other CMakeLists.txt files to use

add_subdirectory("${RNOH_CPP_DIR}" ./rn)

add_library(rnoh_app SHARED
    "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp" "./PackageProvider.cpp")

target_link_libraries(rnoh_app PUBLIC rnoh)

//
// Created on 2026/1/29.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".
#include "RNOH/PackageProvider.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {};
}

修改这个文件 src/main/ets/entryability/EntryAbility.ets

复制代码
import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
import { RNAbility } from '@rnoh/react-native-openharmony';

const DOMAIN = 0x0000;

export default class EntryAbility extends RNAbility {
  protected getPagePath(): string {
    return "pages/Index"
  }
  override onCreate(want: Want): void {
    super.onCreate(want);
    try {
      this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
    } catch (err) {
      hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err));
    }
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
  }

  onDestroy(): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
        return;
      }
      hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
    });
  }

  onWindowStageDestroy(): void {
    // Main window is destroyed, release UI related resources
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground(): void {
    // Ability has brought to foreground
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground(): void {
    // Ability has back to background
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');
  }
}

新建文件 src/main/ets/RNPackagesFactory.ets

复制代码
import { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony/ts';
export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [];
}

修改 harmony\entry\build-profile.json5

复制代码
{
  "apiType": "stageMode",
  "buildOption": {
    "externalNativeOptions":{
      "path":"./src/main/cpp/CMakeLists.txt",
      "arguments":"",
      "cppFlags":"",
      "abiFilters":["arm64-v8a","x86_64"]
    },
    "resOptions": {
      "copyCodeResource": {
        "enable": false
      }
    }
  },
  "buildOptionSet": [
    {
      "name": "release",
      "arkOptions": {
        "obfuscation": {
          "ruleOptions": {
            "enable": false,
            "files": [
              "./obfuscation-rules.txt"
            ]
          }
        }
      }
    },
  ],
  "targets": [
    {
      "name": "default"
    },
    {
      "name": "ohosTest",
    }
  ]
}

修改 index.ets

复制代码
import {
  AnyJSBundleProvider,
  ComponentBuilderContext,
  FileJSBundleProvider,
  MetroJSBundleProvider,
  ResourceJSBundleProvider,
  RNApp,
  RNOHErrorDialog,
  RNOHLogger,
  TraceJSBundleProviderDecorator,
  RNOHCoreContext
} from '@rnoh/react-native-openharmony';
import { createRNPackages } from '../RNPackagesFactory';

@Builder
export function buildCustomRNComponent(ctx: ComponentBuilderContext) {}

const wrappedCustomRNComponentBuilder = wrapBuilder(buildCustomRNComponent)

@Entry
@Component
struct Index {
  @StorageLink('RNOHCoreContext') private rnohCoreContext: RNOHCoreContext | undefined = undefined
  @State shouldShow: boolean = false
  private logger!: RNOHLogger

  aboutToAppear() {
    this.logger = this.rnohCoreContext!.logger.clone("Index")
    const stopTracing = this.logger.clone("aboutToAppear").startTracing();

    this.shouldShow = true
    stopTracing();
  }

  onBackPress(): boolean | undefined {
    // NOTE: this is required since `Ability`'s `onBackPressed` function always
    // terminates or puts the app in the background, but we want Ark to ignore it completely
    // when handled by RN
    this.rnohCoreContext!.dispatchBackPress()
    return true
  }

  build() {
    Column() {
      if (this.rnohCoreContext && this.shouldShow) {
        if (this.rnohCoreContext?.isDebugModeEnabled) {
          RNOHErrorDialog({ ctx: this.rnohCoreContext })
        }
        RNApp({
          rnInstanceConfig: {
            createRNPackages,
            enableNDKTextMeasuring: true, // 该项必须为true,用于开启NDK文本测算
            enableBackgroundExecutor: false,
            enableCAPIArchitecture: true, // 该项必须为true,用于开启CAPI
            arkTsComponentNames: []
          },
          initialProps: { "foo": "bar" } as Record<string, string>,
          appKey: "RNNavigation",
          wrappedCustomRNComponentBuilder: wrappedCustomRNComponentBuilder,
          onSetUp: (rnInstance) => {
            rnInstance.enableFeatureFlag("ENABLE_RN_INSTANCE_CLEAN_UP")
          },
          jsBundleProvider: new TraceJSBundleProviderDecorator(
            new AnyJSBundleProvider([
              new MetroJSBundleProvider(),
              // NOTE: to load the bundle from file, place it in
              // `/data/app/el2/100/base/com.rnoh.tester/files/bundle.harmony.js`
              // on your device. The path mismatch is due to app sandboxing on OpenHarmony
              new FileJSBundleProvider('/data/storage/el2/base/files/bundle.harmony.js'),
              new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'hermes_bundle.hbc'),
              new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'bundle.harmony.js')
            ]),
            this.rnohCoreContext.logger),
        })
      }
    }
    .height('100%')
    .width('100%')
  }
}
  1. 运行项目



    至此,完成了ReactNative for OpenHarmany的工程初始化

模板工程地址:RNNavigation

React Native 三方库使用与集成

通过 react-navigation 实战案例,完成从 三方库引入业务页面实现C-API 高性能架构配置原生模块底层桥接 的全链路开发。

章节一:三方库的选择与集成

在 HarmonyOS RN 开发中,第一步是确保你使用的三方库能够运行在鸿蒙系统上。

1.1 识别适配包 (TPL)

为什么需要适配版本?

在 HarmonyOS RN 中,带有原生代码(C++/ArkUI)的三方库需要经过专门适配才能运行。

  • 命名规范 :通常带有 @react-native-oh-tpl 前缀。
  • 版本匹配 :确保适配包的版本与你项目中的 react-native-harmony 版本兼容。

1.2 安装核心依赖

以导航库为例,安装以下核心组件:

复制代码
# 安装基础导航容器  
npm install @react-navigation/native@6.1.17
# 安装鸿蒙适配的原生组件 (TPL 版本)  
# 提示:^ 符号表示兼容后续小版本更新  
npm install @react-native-oh-tpl/react-native-gesture-handler@^2.14.16  
npm install @react-native-oh-tpl/react-native-safe-area-context@^4.7.4-0.2.1  
npm install @react-native-oh-tpl/react-native-screens@^3.34.0-0.0.1  
npm install @react-native-oh-tpl/stack@6.4.0-0.0.4

章节二:业务页面与导航体系实现

2.1 规范化开发:路由常量

文件: src/constants/routes.ts 操作: 严禁使用硬编码字符串。定义全大写的路由常量,便于在原生侧注册白名单时参考。

复制代码
/**
 * 首页路由常量
 * 对应 Tab 中的第一个页面
 */

export const ROUTE_HOME = 'HOME';

/**
 * 详情页路由常量
 * 用于展示点击列表后的具体内容,演示参数传递
 */

export const ROUTE_DETAILS = 'DETAILS';

/**
 * 教学说明/关于页路由常量
 * 对应 Tab 中的第二个页面
 */

export const ROUTE_INFO = 'INFO';

/**
 * 演示列表页路由常量
 * 用于展示不同的导航案例,演示堆栈跳转
 */

export const ROUTE_DEMO_LIST = 'DEMO_LIST';

/**
 * 标签页导航器路由常量
 * 这是一个"包装路由",它包裹了首页和关于页
 */

export const ROUTE_TAB_NAVIGATOR = 'TAB_NAVIGATOR';

2.2 嵌套导航实现逻辑

文件: RootNavigator.tsx 操作要点:

  1. 初始化 Stack:创建根导航器,负责管理全局页面(如详情页、登录页)。

  2. 初始化 Tabs:创建底部菜单导航器。

  3. 嵌套声明 :将 TabNavigator 作为 Stack.Screen 的一个 component 传入。

    /**

    • @ProjectName : RNNavigation

    • @Author : GuoJiaHui

    • @Time : 2026年04月20日 00:25 AM

    • @Description : 根导航器配置。这里展示了 React Navigation 的灵魂:嵌套导航。

    • 教学点:

      1. 堆栈导航 (Stack):像剥洋葱,一层包一层,适合从列表页跳到详情页。
      1. 标签导航 (Tab):像切频道,平级切换,适合底部菜单。
      1. 嵌套逻辑:Stack 里面可以装 Tab,Tab 里面也可以装 Stack。

    */

    import React from 'react';

    // 核心容器:负责管理整个导航状态

    import {NavigationContainer} from '@react-navigation/native';

    // 堆栈导航器:实现页面推入和弹出的效果

    import {createStackNavigator} from '@react-native-oh-tpl/stack';

    // 底部标签导航器:实现底部 Tab 切换效果

    import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';

    // 导入所有页面

    import HomePage from '../pages/HomePage';

    import DemoListPage from '../pages/DemoListPage';

    import DetailsPage from '../pages/DetailsPage';

    import InfoPage from '../pages/InfoPage';

    // 导入路由常量:统一路由名称,防止手抖写错

    import {

    ROUTE_HOME,

    ROUTE_DEMO_LIST,

    ROUTE_DETAILS,

    ROUTE_INFO,

    ROUTE_TAB_NAVIGATOR,

    } from '../constants/routes';

    // 创建两个导航器工厂实例

    const Stack = createStackNavigator();

    const Tab = createBottomTabNavigator();

    /**

    • 【内层导航】底部标签页导航器

    • 负责应用底部的两个主入口:首页、关于页。

    */

    const TabNavigator = () => {

    console.log('[RootNavigator] 渲染底部 Tab 栏');

    return (

    复制代码
     <Tab.Navigator
    
       screenOptions={{
    
         tabBarActiveTintColor: '#4F46E5', // 选中时的颜色(教学 Indigo 色)
    
         tabBarInactiveTintColor: '#94A3B8', // 未选中时的颜色
    
         headerShown: false, // 隐藏 Tab 内部页面的默认顶部标题,因为我们通常在 Stack 里统一定义
    
         tabBarStyle: {
    
           backgroundColor: '#FFFFFF',
    
           borderTopWidth: 0,
    
           elevation: 10, // 鸿蒙/安卓的阴影
    
           height: 60,
    
           paddingBottom: 8,
    
         },
    
       }}>
    
       <Tab.Screen
    
         name={ROUTE_HOME}
    
         component={HomePage}
    
         options={{tabBarLabel: '首页'}}
    
       />
    
       <Tab.Screen
    
         name={ROUTE_INFO}
    
         component={InfoPage}
    
         options={{tabBarLabel: '关于'}}
    
       />
    
     </Tab.Navigator>

    );

    };

    /**

    • 【外层导航】根堆栈导航器

    • 负责处理全局的页面跳转逻辑。

    */

    export const RootNavigator = () => {

    console.log('[RootNavigator] 初始化全局 Stack 导航');

    return (

    复制代码
     /**
    
      * NavigationContainer 是导航系统的根。
    
      * 所有的导航器(Stack, Tab 等)必须被它包裹。
    
      */
    
     <NavigationContainer>
    
       <Stack.Navigator
    
         initialRouteName={ROUTE_TAB_NAVIGATOR} // 应用启动时首先显示哪个路由
    
         screenOptions={{
    
           // 全局统一的顶部标题栏样式
    
           headerStyle: {
    
             backgroundColor: '#EEF2FF',
    
             elevation: 0, // 去掉阴影,让 UI 看起来更现代、平滑
    
           },
    
           headerTintColor: '#312E81', // 标题和返回按钮的颜色
    
           headerTitleStyle: {fontWeight: 'bold'},
    
           headerBackTitleVisible: false, // 隐藏 iOS 风格的返回文字,只留箭头
    
         }}>
    
         {/*
    
           1. 嵌套路由:第一个页面就是上面的 TabNavigator。
    
           这意味着我们的底部菜单是应用的主框架。
    
         */}
    
         <Stack.Screen
    
           name={ROUTE_TAB_NAVIGATOR}
    
           component={TabNavigator}
    
           options={{headerShown: false}} // 隐藏外层 Stack 的标题,使用内层或不显示
    
         />
    
    
    
         {/*
    
           2. 独立页面:这些页面不在底部菜单里。
    
           当我们在首页点击"开始学习"时,会通过 Stack 把 DemoListPage 推到屏幕前。
    
         */}
    
         <Stack.Screen
    
           name={ROUTE_DEMO_LIST}
    
           component={DemoListPage}
    
           options={{title: '学习演示'}}
    
         />
    
    
    
         {/*
    
           3. 动态标题页面:演示如何根据参数动态设置标题。
    
         */}
    
         <Stack.Screen
    
           name={ROUTE_DETAILS}
    
           component={DetailsPage}
    
           options={({route}: any) => ({
    
             title: route.params?.title || '详情', // 如果传了 title 参数就用它,否则默认显示"详情"
    
           })}
    
         />
    
       </Stack.Navigator>
    
     </NavigationContainer>

    );

    };


章节三:开启 C-API 高性能架构

3.1 核心配置步骤

文件: Index.ets 操作细节:

  1. 启用标志位 :设置 enableCAPIArchitecture: true

  2. 文本测算优化 :设置 enableNDKTextMeasuring: true(这是 C-API 架构下的推荐配置,能大幅提升文字渲染性能)。

  3. 设置 appKey :确保 appKey 与 JS 侧 AppRegistry.registerComponent 的第一个参数完全一致。

    import {
    AnyJSBundleProvider,
    ComponentBuilderContext,
    FileJSBundleProvider,
    MetroJSBundleProvider,
    ResourceJSBundleProvider,
    RNApp,
    RNOHErrorDialog,
    RNOHLogger,
    TraceJSBundleProviderDecorator,
    RNOHCoreContext
    } from '@rnoh/react-native-openharmony';
    import { createRNPackages } from '../RNPackagesFactory';
    import { SAFE_AREA_VIEW_TYPE, SafeAreaView, SAFE_AREA_PROVIDER_TYPE, SafeAreaProvider } from "@react-native-oh-tpl/react-native-safe-area-context";
    import { componentBuilder as RNScreensComponentBuilder } from '@react-native-oh-tpl/react-native-screens';

    @Builder
    export function buildCustomRNComponent(ctx: ComponentBuilderContext) {
    if (ctx.componentName === SAFE_AREA_VIEW_TYPE) {
    SafeAreaView({
    ctx: ctx.rnComponentContext,
    tag: ctx.tag,
    buildCustomComponent: buildCustomRNComponent
    })
    } else if (ctx.componentName === SAFE_AREA_PROVIDER_TYPE) {
    SafeAreaProvider({
    ctx: ctx.rnComponentContext,
    tag: ctx.tag,
    buildCustomComponent: buildCustomRNComponent
    })
    } else {
    RNScreensComponentBuilder(ctx)
    }
    }

    const wrappedCustomRNComponentBuilder = wrapBuilder(buildCustomRNComponent)

    @Entry
    @Component
    struct Index {
    @StorageLink('RNOHCoreContext') private rnohCoreContext: RNOHCoreContext | undefined = undefined
    @State shouldShow: boolean = false
    private logger!: RNOHLogger

    aboutToAppear() {
    this.logger = this.rnohCoreContext!.logger.clone("Index")
    const stopTracing = this.logger.clone("aboutToAppear").startTracing();

    复制代码
     this.shouldShow = true  
     stopTracing();  

    }

    onBackPress(): boolean | undefined {
    // NOTE: this is required since Ability's onBackPressed function always
    // terminates or puts the app in the background, but we want Ark to ignore it completely // when handled by RN this.rnohCoreContext!.dispatchBackPress()
    return true
    }

    build() {
    Column() {
    if (this.rnohCoreContext && this.shouldShow) {
    if (this.rnohCoreContext?.isDebugModeEnabled) {
    RNOHErrorDialog({ ctx: this.rnohCoreContext })
    }
    RNApp({
    rnInstanceConfig: {
    createRNPackages,
    enableNDKTextMeasuring: true, // 该项必须为true,用于开启NDK文本测算
    enableBackgroundExecutor: false,
    enableCAPIArchitecture: true, // 该项必须为true,用于开启CAPI
    arkTsComponentNames: [
    SAFE_AREA_VIEW_TYPE,
    SAFE_AREA_PROVIDER_TYPE,
    "RNSScreen",
    "RNSScreenContainer",
    "RNSScreenNavigationContainer",
    "RNSScreenStack",
    "RNSScreenStackHeaderConfig",
    "RNSScreenStackHeaderSubview",
    "RNSFullWindowOverlay",
    "RNSModalScreen",
    "RNSSearchBar"
    ]
    },
    initialProps: { "foo": "bar" } as Record<string, string>,
    appKey: "rn-navigation",
    wrappedCustomRNComponentBuilder: wrappedCustomRNComponentBuilder,
    onSetUp: (rnInstance) => {
    rnInstance.enableFeatureFlag("ENABLE_RN_INSTANCE_CLEAN_UP")
    },
    jsBundleProvider: new TraceJSBundleProviderDecorator(
    new AnyJSBundleProvider([
    new MetroJSBundleProvider(),
    // NOTE: to load the bundle from file, place it in
    // /data/app/el2/100/base/com.rnoh.tester/files/bundle.harmony.js // on your device. The path mismatch is due to app sandboxing on OpenHarmony new FileJSBundleProvider('/data/storage/el2/base/files/bundle.harmony.js'),
    new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'hermes_bundle.hbc'),
    new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'bundle.harmony.js')
    ]),
    this.rnohCoreContext.logger),
    })
    }
    } .height('100%')
    .width('100%')
    }
    }


章节四:原生模块底层桥接

这是最核心的步骤,决定了三方库的原生功能(如手势、屏幕管理)能否被 JS 调用。

4.1 第一步:Native 依赖链接 (ohpm)

harmony/oh-package.json5 中链接本地 HAR 包,并使用 overrides 确保所有模块引用的 RNOH 版本一致。

复制代码
{  
  "modelVersion": "6.0.2",  
  "description": "Please describe the basic information.",  
  "dependencies": {  
    "@rnoh/react-native-openharmony": "0.72.90",  
    "@react-native-oh-tpl/react-native-safe-area-context": "file:../node_modules/@react-native-oh-tpl/react-native-safe-area-context/harmony/safe_area.har",  
    "@react-native-oh-tpl/react-native-gesture-handler": "file:../node_modules/@react-native-oh-tpl/react-native-gesture-handler/harmony/gesture_handler.har",  
    "@react-native-oh-tpl/react-native-screens": "file:../node_modules/@react-native-oh-tpl/react-native-screens/harmony/screens.har"  
  },  
  "overrides": {  
    "@rnoh/react-native-openharmony": "0.72.90"  
  },  
  "devDependencies": {  
    "@ohos/hypium": "1.0.25",  
    "@ohos/hamock": "1.0.0"  
  },  
  "dynamicDependencies": {}  
}

4.2 第二步:C++ 源码链接 (CMake)

harmony/entry/src/main/cpp/CMakeLists.txt 中引入三方库的 C++ 部分。

复制代码
project(rnapp)  
cmake_minimum_required(VERSION 3.28)  
  
#  核心修复:强制 Ninja 将超长参数写入临时 .rsp 文件,绕过 Windows 命令行长度限制  
set(CMAKE_NINJA_FORCE_RESPONSE_FILE "ON" CACHE BOOL "Force response file usage" FORCE)  
  
set(CMAKE_SKIP_BUILD_RPATH TRUE)  
set(OH_MODULE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../oh_modules")  
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")  
  
set(RNOH_CPP_DIR "${OH_MODULE_DIR}/@rnoh/react-native-openharmony/src/main/cpp")  
set(RNOH_GENERATED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/generated")  
set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments")  
set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")  
add_compile_definitions(WITH_HITRACE_SYSTRACE)  
set(WITH_HITRACE_SYSTRACE 1) # for other CMakeLists.txt files to use  
  
add_subdirectory("${RNOH_CPP_DIR}" ./rn)  
  
# 包含 codegen 生成的源码  
file(GLOB_RECURSE GENERATED_SRC "${RNOH_GENERATED_DIR}/*.cpp")  
  
# RNOH_BEGIN: add_package_subdirectories  
add_subdirectory("${OH_MODULE_DIR}/@react-native-oh-tpl/react-native-safe-area-context/src/main/cpp" ./safe_area)  
add_subdirectory("${OH_MODULE_DIR}/@react-native-oh-tpl/react-native-gesture-handler/src/main/cpp" ./gesture_handler)  
add_subdirectory("${OH_MODULE_DIR}/@react-native-oh-tpl/react-native-screens/src/main/cpp" ./screens)  
# RNOH_END: add_package_subdirectories  
  
add_library(rnoh_app SHARED  
    "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"   
    "./PackageProvider.cpp"  
    ${GENERATED_SRC}  
)  
  
target_include_directories(rnoh_app PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")  
target_link_libraries(rnoh_app PUBLIC rnoh)  
  
# RNOH_BEGIN: link_packages  
target_link_libraries(rnoh_app PUBLIC rnoh_safe_area)  
target_link_libraries(rnoh_app PUBLIC rnoh_gesture_handler)  
target_link_libraries(rnoh_app PUBLIC rnoh_screens)  
# RNOH_END: link_packages

4.3 第三步:Codegen 自动生成胶水代码

运行 Codegen 工具,根据 JS 定义自动生成 C++ 的 TurboModule 声明和 JSI 绑定代码。

复制代码
npx react-native codegen-harmony --rnoh-module-path ./harmony/oh_modules/@rnoh/react-native-openharmony

生成产物 :位于 harmony/entry/src/main/cpp/generated

Pasted image 20260420230702.png

4.4 第四步:原生包注册 (PackageProvider.cpp)

文件参考 :PackageProvider.cpp 在 C++ 侧同时注册 Codegen 生成包三方库原生包

复制代码
#include "RNOH/PackageProvider.h"  
#include "generated/RNOHGeneratedPackage.h"  
#include "SafeAreaViewPackage.h"  
#include "RnohReactNativeHarmonyGestureHandlerPackage.h"  
#include "RnohReactNativeHarmonyScreensPackage.h"  
  
using namespace rnoh;  
  
std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {  
    return {  
        std::make_shared<RNOHGeneratedPackage>(ctx),  
        std::make_shared<SafeAreaViewPackage>(ctx),  
        std::make_shared<RnohReactNativeHarmonyGestureHandlerPackage>(ctx),  
        std::make_shared<RnohReactNativeHarmonyScreensPackage>(ctx)  
    };  
}

4.5 第五步:ArkTS 工厂注册 (RNPackagesFactory.ets)

文件参考 :RNPackagesFactory.ets 在 ArkTS 侧导出 Package 实例。

复制代码
import { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony/ts';  
import { SafeAreaViewPackage } from '@react-native-oh-tpl/react-native-safe-area-context/ts';  
import RNGestureHandlerPackage from '@react-native-oh-tpl/react-native-gesture-handler';  
import RNOHScreensPackage from '@react-native-oh-tpl/react-native-screens';  
  
export function createRNPackages(ctx: RNPackageContext): RNPackage[] {  
  return [  
    new SafeAreaViewPackage(ctx),  
    new RNGestureHandlerPackage(ctx),  
    new RNOHScreensPackage(ctx)  
  ];  
}

章节五:白名单与组件构建器

在 C-API 架构下,某些组件仍需通过 ArkTS 渲染,必须在 Index.ets 中显式声明。

5.1 ArkTS 组件白名单

arkTsComponentNames 数组中填入需要 ArkTS 参与渲染的组件名(如 RNSScreenStack)。

复制代码
import {  
  AnyJSBundleProvider,  
  ComponentBuilderContext,  
  FileJSBundleProvider,  
  MetroJSBundleProvider,  
  ResourceJSBundleProvider,  
  RNApp,  
  RNOHErrorDialog,  
  RNOHLogger,  
  TraceJSBundleProviderDecorator,  
  RNOHCoreContext  
} from '@rnoh/react-native-openharmony';  
import { createRNPackages } from '../RNPackagesFactory';  
import { SAFE_AREA_VIEW_TYPE, SafeAreaView, SAFE_AREA_PROVIDER_TYPE, SafeAreaProvider } from "@react-native-oh-tpl/react-native-safe-area-context";  
import { componentBuilder as RNScreensComponentBuilder } from '@react-native-oh-tpl/react-native-screens';  
  
@Builder  
export function buildCustomRNComponent(ctx: ComponentBuilderContext) {  
  if (ctx.componentName === SAFE_AREA_VIEW_TYPE) {  
    SafeAreaView({  
      ctx: ctx.rnComponentContext,  
      tag: ctx.tag,  
      buildCustomComponent: buildCustomRNComponent  
    })  
  } else if (ctx.componentName === SAFE_AREA_PROVIDER_TYPE) {  
    SafeAreaProvider({  
      ctx: ctx.rnComponentContext,  
      tag: ctx.tag,  
      buildCustomComponent: buildCustomRNComponent  
    })  
  } else {  
    RNScreensComponentBuilder(ctx)  
  }  
}  
  
const wrappedCustomRNComponentBuilder = wrapBuilder(buildCustomRNComponent)  
  
@Entry  
@Component  
struct Index {  
  @StorageLink('RNOHCoreContext') private rnohCoreContext: RNOHCoreContext | undefined = undefined  
  @State shouldShow: boolean = false  
  private logger!: RNOHLogger  
  
  aboutToAppear() {  
    this.logger = this.rnohCoreContext!.logger.clone("Index")  
    const stopTracing = this.logger.clone("aboutToAppear").startTracing();  
  
    this.shouldShow = true  
    stopTracing();  
  }  
  
  onBackPress(): boolean | undefined {  
    // NOTE: this is required since `Ability`'s `onBackPressed` function always  
    // terminates or puts the app in the background, but we want Ark to ignore it completely    // when handled by RN    this.rnohCoreContext!.dispatchBackPress()  
    return true  
  }  
  
  build() {  
    Column() {  
      if (this.rnohCoreContext && this.shouldShow) {  
        if (this.rnohCoreContext?.isDebugModeEnabled) {  
          RNOHErrorDialog({ ctx: this.rnohCoreContext })  
        }  
        RNApp({  
          rnInstanceConfig: {  
            createRNPackages,  
            enableNDKTextMeasuring: true, // 该项必须为true,用于开启NDK文本测算  
            enableBackgroundExecutor: false,  
            enableCAPIArchitecture: true, // 该项必须为true,用于开启CAPI  
            arkTsComponentNames: [  
              SAFE_AREA_VIEW_TYPE,   
SAFE_AREA_PROVIDER_TYPE,  
              "RNSScreen",  
              "RNSScreenContainer",  
              "RNSScreenNavigationContainer",  
              "RNSScreenStack",  
              "RNSScreenStackHeaderConfig",  
              "RNSScreenStackHeaderSubview",  
              "RNSFullWindowOverlay",  
              "RNSModalScreen",  
              "RNSSearchBar"  
            ]  
          },  
          initialProps: { "foo": "bar" } as Record<string, string>,  
          appKey: "rn-navigation",  
          wrappedCustomRNComponentBuilder: wrappedCustomRNComponentBuilder,  
          onSetUp: (rnInstance) => {  
            rnInstance.enableFeatureFlag("ENABLE_RN_INSTANCE_CLEAN_UP")  
          },  
          jsBundleProvider: new TraceJSBundleProviderDecorator(  
            new AnyJSBundleProvider([  
              new MetroJSBundleProvider(),  
              // NOTE: to load the bundle from file, place it in  
              // `/data/app/el2/100/base/com.rnoh.tester/files/bundle.harmony.js`              // on your device. The path mismatch is due to app sandboxing on OpenHarmony              new FileJSBundleProvider('/data/storage/el2/base/files/bundle.harmony.js'),  
              new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'hermes_bundle.hbc'),  
              new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'bundle.harmony.js')  
            ]),  
            this.rnohCoreContext.logger),  
        })  
      }  
    }    .height('100%')  
    .width('100%')  
  }  
}

5.2 委托构建器

使用三方库提供的 componentBuilder 来处理这些组件的创建。

复制代码
if (ctx.componentName === "RNSScreenStack") {  
  RNScreensComponentBuilder(ctx);  
}

总结:集成全景图

  1. JS 层:安装 TPL 依赖,编写业务代码。
  2. 构建层:运行 Codegen 生成 C++ 桥接文件。
  3. C++ 层 :CMake 链接源码,PackageProvider 注册生成的包和三方库包。
  4. ArkTS 层RNPackagesFactory 导出实例,Index.ets 配置白名单和构建器。

掌握了这套路线,你就能在 HarmonyOS 环境中游刃有余地集成任何复杂的 React Native 三方库。

相关推荐
一行代码一行诗++1 小时前
C语言中scanf详解
c语言·开发语言
ZenosDoron1 小时前
keil软件修改字体,Asm editor,和C/C++ editor的区别
c语言·开发语言·c++
yuan199972 小时前
C&CG(列与约束生成)算法,来解决“风光随机性”下的微网鲁棒配置问题
c语言·开发语言·算法
LeocenaY2 小时前
C语言面试题总结
c语言·开发语言·数据结构
爱吃芹菜炒肉3 小时前
Chapter 16: Power Management
服务器·c语言·网络·tcp/ip·pcie
Rabitebla4 小时前
【数据结构】动态顺序表实现详解:从原理到接口设计(面试视角)
c语言·开发语言·数据结构·c++·面试·职场和发展
IntMainJhy5 小时前
Flutter 三方库 ImageCropper 图片裁剪鸿蒙化适配与实战指南(正方形+自定义比例全覆盖)
flutter·华为·harmonyos
YSF2017_35 小时前
C语言-12-静态库制作
c语言·开发语言
IntMainJhy5 小时前
Flutter for OpenHarmony 第三方库六大核心模块整合实战全解|从图片处理、消息通知到加密存储、设备推送 一站式鸿蒙适配开发总结
flutter·华为·harmonyos
key_3_feng5 小时前
HarmonyOS 6.0 元服务(Meta Ability)深度设计方案
pytorch·深度学习·harmonyos·元服务