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

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 可用。

bash 复制代码
node -v
npm -v

代码解释:

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

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

text 复制代码
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 示例:

text 复制代码
{DevEco Studio安装路径}/sdk/{SDK版本}/openharmony/toolchains
HDC_SERVER_PORT=7035

代码解释:

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

Mac 示例:

bash 复制代码
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. 如果团队已经约定其他端口,按团队配置来。

验证:

bash 复制代码
hdc -v
hdc list targets

代码解释:

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

4. 配置 CAPI 架构变量

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

text 复制代码
RNOH_C_API_ARCH=1

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

text 复制代码
变量名:RNOH_C_API_ARCH
变量值:1

Mac 或 Linux:

bash 复制代码
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 命令为示例。

bash 复制代码
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 版本:

json 复制代码
{
  "dependencies": {
    "react-native": "0.72.5"
  }
}

代码解释:

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

6. 安装鸿蒙化 RN 依赖

官方文档使用占位版本:

bash 复制代码
npm i @react-native-oh/react-native-harmony@x.x.x

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

bash 复制代码
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 目标。官方和实操文章都给出了类似配置。

javascript 复制代码
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 中加入:

json 复制代码
{
  "scripts": {
    "dev": "react-native bundle-harmony --dev"
  }
}

执行:

bash 复制代码
npm run dev

代码解释:

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

8. 创建或准备鸿蒙工程

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

text 复制代码
DevEco Studio -> New Project -> Empty Ability -> Compile SDK API13

说明:

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

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

bash 复制代码
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

cmake 复制代码
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

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++ 构建接入模块构建。

json5 复制代码
{
  "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

typescript 复制代码
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

typescript 复制代码
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 注册的名字一致。

typescript 复制代码
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 侧入口通常类似:

javascript 复制代码
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 后,通常会有:

text 复制代码
AwesomeProject/harmony/entry/src/main/resources/rawfile/bundle.harmony.js
AwesomeProject/harmony/entry/src/main/resources/rawfile/assets

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

text 复制代码
MyApplication/entry/src/main/resources/rawfile/

代码解释:

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

hdc 推送示例:

bash 复制代码
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
相关推荐
●VON1 小时前
HarmonyKit | 鸿蒙新特性对比:Tabs vs HdsTabs 选型深度解析
华为·harmonyos·鸿蒙·新特性
weixin_400005601 小时前
Vision-Language-Action:LMDrive项目架构与核心算法组件
人工智能·深度学习·算法·机器学习·架构·自动驾驶
最爱老式锅包肉1 小时前
《HarmonyOS技术精讲-Core Speech Kit(基础语音服务)》第1篇:音频管理基础与语音服务入门
华为·音视频·harmonyos
最爱老式锅包肉2 小时前
HarmonyOS技术精讲-Speech Kit(场景化语音服务):AI字幕控件赋能实时语音识别与显示
语音识别·harmonyos
千逐682 小时前
Uniapp 鸿蒙实战之 AtomGit APP - 首页设计与仓库列表实现
华为·uni-app·harmonyos
kgduu2 小时前
react-redux学习笔记
笔记·学习·react.js
FriendshipT2 小时前
Ultralytics:解读PSABlock模块
人工智能·pytorch·python·深度学习·目标检测
minxihou2 小时前
TRINITY-Router: 用数据证伪LLM路由假设 - 8模型316题实验报告
人工智能·深度学习·语言模型·智能路由器
binbin_522 小时前
Flutter 调用鸿蒙原生组件:MethodChannel 与 PlatformView 的选择和落地
开发语言·深度学习·flutter·harmonyos