React Native 鸿蒙环境搭建完整实战:从 RN 工程到 RNOH 运行

React Native 跑鸿蒙不是“装完 Node 再创建一个 RN 项目”这么简单。真正容易出错的地方在中间链路:hdc 找不到设备、RNOH_C_API_ARCH 没配、RN 侧没有生成 bundle.harmony.js、鸿蒙侧没有接入 RNOH 的 C++ 和 ArkTS 代码、RNAppappKey 和 RN 入口不一致。任何一处错了,最后表现都可能是白屏、编译失败或设备连不上。

在这里插入图片描述

本文结合 CPF-RN 官方环境搭建文档和一篇实操文章整理,目标是把一条可理解、可排查的 React Native 鸿蒙搭建链路写清楚。官方文档中依赖版本使用 x.x.x 占位,实操文章采用了 React Native 0.72.5@react-native-oh/react-native-harmony@0.72.53@rnoh/react-native-openharmony@0.72.53 这一组示例。实际项目应以官方发布版本、团队锁定版本和当前工程模板为准,不要把示例版本机械套到所有项目。

在这里插入图片描述

在这里插入图片描述

1. 先理解 RN 鸿蒙的两段工程

React Native 鸿蒙一般会同时涉及两个工程视角:RN 侧生成 JS bundle,鸿蒙侧通过 RNOH 容器加载 bundle 并运行。

部分 负责内容 常见文件
RN 工程 JS/TS 业务代码、Metro、bundle 生成 package.jsonmetro.config.jsApp.tsx
鸿蒙工程 DevEco 构建、RNOH 容器、C++ 适配层 entryIndex.etsCMakeLists.txt
RNOH 依赖 RN 和 OpenHarmony 的桥接层 @react-native-oh/*@rnoh/*
bundle 资源 RN 运行入口产物 bundle.harmony.jsassets

这也是为什么只创建 RN 工程不够,必须把 RN 侧产物接入鸿蒙侧。

2. 准备 Node、DevEco Studio 和 SDK

先安装 Node.js,并确认 nodenpm 可用。

node -v
npm -v

代码解释:

  1. node -v 用来确认 Node 已安装。
  2. npm -v 用来确认 npm 可用。
  3. 如果命令不存在,先修 Node 环境,不要继续执行 RN 初始化。

然后安装 DevEco Studio,并在 IDE 内完成 SDK 下载和环境配置。官方文档强调 DevEco Studio 开发环境依赖网络环境,首次配置时要保持网络可用。

DevEco Studio -> SDK Manager -> 安装 OpenHarmony SDK 与工具链

说明:

  1. DevEco Studio 负责鸿蒙工程创建、构建和运行。
  2. OpenHarmony SDK 中的 toolchains 目录提供 hdc
  3. 实操文章提到 DevEco Studio API 版本要大于 13;官方文档创建示例工程时使用 Compile SDK API13。如果你使用更新模板,应以当前 RNOH 版本支持范围和项目要求为准。

3. 配置 hdc 和端口

hdc 是 OpenHarmony 调试工具,React Native 鸿蒙工程真机调试也会用到它。官方文档要求把 SDK 下的 openharmony/toolchains 加到环境变量。

Windows 示例:

{DevEco Studio安装路径}/sdk/{SDK版本}/openharmony/toolchains
HDC_SERVER_PORT=7035

代码解释:

  1. toolchains 要写完整真实路径。
  2. HDC_SERVER_PORT 可以设置为未被占用端口,官方示例和实操文章都使用 7035
  3. 配置完建议重新打开终端。

Mac 示例:

export PATH="/Applications/DevEco-Studio.app/Contents/sdk/{版本路径}/openharmony/toolchains:$PATH"
export HDC_SERVER_PORT=7035
launchctl setenv HDC_SERVER_PORT $HDC_SERVER_PORT

代码解释:

  1. Mac 路径要按 DevEco Studio 实际安装位置替换。
  2. launchctl setenv 可以让图形应用也拿到端口变量。
  3. 如果团队已经约定其他端口,按团队配置来。

验证:

hdc -v
hdc list targets

代码解释:

  1. hdc -v 能输出版本,说明 PATH 生效。
  2. hdc list targets 能看到设备或模拟器,说明连接链路基本可用。

4. 配置 CAPI 架构变量

官方文档说明,当前 RN 框架提供的 Demo 工程默认为 CAPI 版本,需要配置:

RNOH_C_API_ARCH=1

Windows 在系统环境变量中新建:

变量名:RNOH_C_API_ARCH
变量值:1

Mac 或 Linux:

export RNOH_C_API_ARCH=1
echo $RNOH_C_API_ARCH

代码解释:

  1. 这个变量影响 RNOH CAPI 架构相关构建。
  2. echo 输出 1 才说明当前终端已经生效。
  3. 如果 DevEco Studio 从桌面启动,Mac 还要注意 IDE 进程是否拿到了环境变量。

5. 创建 React Native 工程

实操文章使用 RN 0.72.5。官方文档也以 0.72.5 命令为示例。

npx react-native@0.72.5 init AwesomeProject --version 0.72.5 --skip-install
cd AwesomeProject
npm install

代码解释:

  1. --version 0.72.5 锁定 RN 版本。
  2. --skip-install 可以先生成工程,再手动控制依赖安装。
  3. 如果你不想跳过安装,也可以使用官方普通初始化命令。

确认 package.json 中 RN 版本:

{
  "dependencies": {
    "react-native": "0.72.5"
  }
}

代码解释:

  1. RN 版本要和鸿蒙化依赖版本匹配。
  2. 不建议 RN 主版本随意升级后继续使用旧 RNOH 包。

6. 安装鸿蒙化 RN 依赖

官方文档使用占位版本:

npm i @react-native-oh/react-native-harmony@x.x.x

实操文章给出的具体示例是:

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

代码解释:

  1. @react-native-oh/react-native-harmony 用于 RN 侧适配 OpenHarmony。
  2. 官方文档中的 x.x.x 应替换为当前官方发布版本。
  3. 如果你采用 0.72.5 RN,实操文章的 0.72.53 是一个可参考组合,但仍建议以官方 release 和项目模板为准。

7. 配置 metro.config.js 并生成 bundle

RN 侧要让 Metro 知道 Harmony 目标。官方和实操文章都给出了类似配置。

const {mergeConfig, getDefaultConfig} = require('@react-native/metro-config');
const {createHarmonyMetroConfig} = require('@react-native-oh/react-native-harmony/metro.config');

const config = {
  transformer: {
    getTransformOptions: async () => ({
      transform: {
        experimentalImportSupport: false,
        inlineRequires: true,
      },
    }),
  },
};

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

代码解释:

  1. createHarmonyMetroConfig 是 Harmony 目标的关键配置。
  2. reactNativeHarmonyPackageName 要和安装的包名一致。
  3. 这段配置建议整体替换原 metro.config.js 后再运行 bundle 命令。

package.jsonscripts 中加入:

{
  "scripts": {
    "dev": "react-native bundle-harmony --dev"
  }
}

执行:

npm run dev

代码解释:

  1. 成功后会生成 bundle.harmony.js
  2. 生成目录通常在 harmony/entry/src/main/resources/rawfile
  3. 如果报 'react-native' 不是内部或外部命令,先重新执行 npm install

8. 创建或准备鸿蒙工程

官方文档建议新建工程或在已有工程中集成。创建新工程时,示例使用 Compile SDK API13,项目名示例为 MyApplication

DevEco Studio -> New Project -> Empty Ability -> Compile SDK API13

说明:

  1. API13 是官方文档示例,不代表所有版本都只能用 API13。
  2. 项目路径不要太长,Windows 下尤其容易因为路径和构建缓存导致问题。
  3. 新建后等待 IDE 的 SyncData、ohpm install 等动作完成。

进入鸿蒙工程的 entry 目录安装 RNOH 依赖:

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

代码解释:

  1. 官方文档写法是 @x.x.x,实操文章示例为 0.72.53
  2. @rnoh/react-native-openharmony 是鸿蒙侧 RNOH 容器依赖。
  3. har 包较大,必须等 ohpm install 和 IDE 同步完成。

9. 补充 C++ 适配层

entry/src/main 下新建 cpp 目录,并添加 CMakeLists.txt

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)

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

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

target_link_libraries(rnoh_app PUBLIC rnoh)

代码解释:

  1. RNOH_CPP_DIR 指向 ohpm 安装后的 RNOH C++ 目录。
  2. add_subdirectory 把 RNOH 适配层加入构建。
  3. rnoh_app 是官方要求的 so 命名,自定义 CMake 时也要注意名称。

新增 PackageProvider.cpp

#include "RNOH/PackageProvider.h"

using namespace rnoh;

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

代码解释:

  1. 没有自定义 TurboModule 或 Fabric 组件时返回空数组。
  2. 后续接三方库或自定义模块时,在这里补 package。

10. 修改 build-profile.json5

打开 entry/build-profile.json5,把 C++ 构建接入模块构建。

{
  "buildOption": {
    "externalNativeOptions": {
      "path": "./src/main/cpp/CMakeLists.txt",
      "arguments": "",
      "cppFlags": ""
    }
  }
}

代码解释:

  1. path 指向刚才新增的 CMakeLists。
  2. 如果运行 x86_64 架构模拟器,官方文档提示可能需要额外配置 abiFilters 并包含 x86_64
  3. 默认通常面向 arm64-v8a,真机调试时更常见。

11. 补充 ArkTS 入口代码

EntryAbility.ets 改为继承 RNAbility

import { RNAbility } from '@rnoh/react-native-openharmony';

export default class EntryAbility extends RNAbility {
  getPagePath() {
    return 'pages/Index';
  }
}

代码解释:

  1. RNAbility 内部处理了 RNOH 运行需要的生命周期逻辑。
  2. 如果你重写生命周期函数,要调用 super,避免 RNOH 原有逻辑丢失。
  3. getPagePath 返回 ArkTS 入口页面路径。

新增 entry/src/main/ets/RNPackagesFactory.ets

import { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony/ts';

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [];
}

代码解释:

  1. 没有三方库、自定义 TurboModule 或 Fabric 组件时返回空数组。
  2. 后续接原生模块时从这里扩展。

12. 在 Index.ets 中创建 RNApp

Index.ets 是 RNOH 运行 RN bundle 的关键位置。最容易出错的是 appKey,它必须和 RN 侧 AppRegistry.registerComponent 注册的名字一致。

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');
    this.shouldShow = true;
  }

  onBackPress(): boolean | undefined {
    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,
            enableBackgroundExecutor: false,
            enableCAPIArchitecture: true,
            arkTsComponentNames: []
          },
          initialProps: { foo: 'bar' } as Record<string, string>,
          appKey: 'AwesomeProject',
          wrappedCustomRNComponentBuilder,
          jsBundleProvider: new TraceJSBundleProviderDecorator(
            new AnyJSBundleProvider([
              new MetroJSBundleProvider(),
              new FileJSBundleProvider('/data/storage/el2/base/files/bundle.harmony.js'),
              new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'bundle.harmony.js')
            ]),
            this.rnohCoreContext.logger
          )
        });
      }
    }
    .height('100%')
    .width('100%');
  }
}

代码解释:

  1. enableCAPIArchitecture: true 要和前面的 RNOH_C_API_ARCH=1 对齐。
  2. appKey: 'AwesomeProject' 要和 RN 侧 AppRegistry.registerComponent 的 appName 一致。
  3. MetroJSBundleProvider 适合开发阶段从 Metro 加载。
  4. ResourceJSBundleProvider 适合从 rawfile 资源加载 bundle.harmony.js
  5. FileJSBundleProvider 适合从应用沙箱路径加载 bundle。

RN 侧入口通常类似:

import { AppRegistry } from 'react-native';
import App from './App';
import { name as appName } from './app.json';

AppRegistry.registerComponent(appName, () => App);

代码解释:

  1. 如果 app.json 里的 name 是 AwesomeProject,ArkTS 侧 appKey 也要写 AwesomeProject
  2. appKey 不一致是白屏高发原因。

13. 加载 bundle 并运行

RN 侧生成 bundle 后,通常会有:

AwesomeProject/harmony/entry/src/main/resources/rawfile/bundle.harmony.js
AwesomeProject/harmony/entry/src/main/resources/rawfile/assets

bundle.harmony.jsassets 拷贝到鸿蒙工程:

MyApplication/entry/src/main/resources/rawfile/

代码解释:

  1. 如果使用 ResourceJSBundleProvider,bundle 要放在 rawfile。
  2. 如果 bundle 中包含本地图片,assets 也要一起拷贝。
  3. 如果使用 FileJSBundleProvider,可以通过 hdc 把 bundle 推送到应用沙箱。

hdc 推送示例:

hdc file send ./bundle.harmony.js /data/storage/el2/base/files/bundle.harmony.js

代码解释:

  1. 目标路径要和 FileJSBundleProvider 中配置的路径一致。
  2. 沙箱路径可能随应用和系统环境不同而变化,按设备实际路径确认。

最后用 DevEco Studio 运行鸿蒙工程。运行成功后,RN 页面应出现在鸿蒙应用中。

14. 常见问题和处理方式

现象 高概率原因 处理方式
hdc 找不到 toolchains 没加 PATH 重新配置 SDK toolchains 路径
设备列表为空 端口或设备连接问题 检查 HDC_SERVER_PORT、模拟器、真机授权
C++ 编译失败 CMakeLists 或 ohpm 依赖没同步 等 IDE 同步完成,检查 OH_MODULE_DIR
启动白屏 appKey 不匹配或 bundle 没加载 对齐 AppRegistryRNApp appKey
找不到 bundle rawfile 没拷贝或路径不一致 确认 bundle.harmony.js 位置
CAPI 相关错误 RNOH_C_API_ARCH 未配置 设置为 1 并重启终端/IDE
ohpm 安装很慢 har 包较大或网络差 保持网络稳定,等待 SyncData 完成

15. 最终验证清单

  1. node -vnpm -v 正常。
  2. DevEco Studio 已安装,并能创建鸿蒙工程。
  3. OpenHarmony SDK toolchains 已加入 PATH。
  4. HDC_SERVER_PORT 已配置,示例值为 7035
  5. hdc list targets 能看到设备或模拟器。
  6. RNOH_C_API_ARCH=1 生效。
  7. RN 工程使用的 RN 版本与鸿蒙化依赖版本匹配。
  8. metro.config.js 已接入 createHarmonyMetroConfig
  9. npm run dev 能生成 bundle.harmony.js
  10. 鸿蒙工程已安装 @rnoh/react-native-openharmony
  11. C++ 侧有 CMakeLists.txtPackageProvider.cpp
  12. build-profile.json5 已接入 CMake。
  13. EntryAbility 继承 RNAbility
  14. Index.etsRNApp appKey 和 RN 侧 appName 一致。
  15. rawfile 或沙箱路径中能找到 bundle。
  16. DevEco Studio 能正常运行鸿蒙工程。

16. 总结

React Native 鸿蒙环境搭建的核心是把三条线对齐:工具链线、RN 线、鸿蒙 RNOH 线。工具链线解决 DevEco、SDK、hdc 和 CAPI;RN 线解决 React Native 版本、Metro 配置和 bundle;鸿蒙 RNOH 线解决 ohpm 依赖、C++ 适配层、ArkTS 入口和 RNApp 加载。只要按这个顺序推进,遇到问题时就能快速判断是设备连接、bundle 生成、C++ 构建还是 appKey 配置出错。

参考出处

本文结合以下两篇资料整理:

  1. CPF-RN 官方文档:https://gitcode.com/CPF-RN/ohos_react_native/blob/master/docs/zh-cn/环境搭建.md?isLogin=1
  2. CSDN 实操文章:https://blog.csdn.net/m0_65369051/article/details/147123793
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐