React Native for 鸿蒙0.72.5 环境搭建指南

React Native for 鸿蒙0.72.5 环境搭建指南

目录

前置条件

在开始之前,请确保您的开发环境满足以下要求:

  • 操作系统: macOS 10.15+ 或 Windows 10+
  • Node.js: 版本 16 或更高
  • DevEco Studio: 最新版本
  • OpenHarmony SDK: API 21
  • React Native: 0.72.5 版本

环境变量设置

1. 配置 HDC 工具路径

打开终端,执行以下命令编辑配置文件:

bash 复制代码
# 对于 zsh 用户(推荐)
open ~/.zshrc

# 对于 bash 用户
vi ~/.bash_profile

在配置文件中添加以下内容:

bash 复制代码
# 添加 HDC 工具路径到 PATH(注意您的实际 SDK 安装路径)
export PATH="/Users/jianguo/Library/OpenHarmony/Sdk/20/openharmony/toolchains:$PATH" 

# 设置 HDC 服务器端口
HDC_SERVER_PORT=7035 
launchctl setenv HDC_SERVER_PORT $HDC_SERVER_PORT 
export HDC_SERVER_PORT

注意 : HDC 端口变量名为 HDC_SERVER_PORT,变量值可设置为任意未被占用的端口,如 7035

2. 配置 CAPI 版本环境变量

当前 RN 框架提供的 Demo 工程默认为 CAPI 版本,您需要配置环境变量:

bash 复制代码
export RNOH_C_API_ARCH=1

将上述命令添加到您的 shell 配置文件中(~/.bash_profile~/.bashrc~/.zshrc)。

3. 使配置生效

编辑完成后,执行以下命令使配置的环境变量生效:

bash 复制代码
# 对于 zsh 用户
source ~/.zshrc

# 对于 bash 用户
source ~/.bash_profile

4. 验证配置

重新打开终端,检查环境变量是否设置成功:

bash 复制代码
echo $RNOH_C_API_ARCH
echo $HDC_SERVER_PORT

创建 React Native 项目

1. 创建新项目

使用 React Native 内置的命令行工具来创建一个新项目。目前 React Native for OpenHarmony 仅支持 0.72.5 版本的 React Native:

bash 复制代码
npx react-native@0.72.5 init AwesomeDemo --version 0.72.5

2. 跳过 iOS 依赖安装(可选)

该命令在 macOS 环境下初始化 React Native 项目时会下载 iOS 依赖库,耗时较长。如果您只开发鸿蒙项目,可以选择跳过该过程:

bash 复制代码
npx react-native@0.72.5 init AwesomeDemo --version 0.72.5 --skip-install
复制代码
npx react-native@0.72.5 init RnDemo --version 0.72.5 --skip-install

npm i @react-native-oh/react-native-harmony@0.77.40
npx react-native@0.72.5 init AwesomeDemo --version 0.72.5 --skip-install

提示: 跳过 iOS 依赖安装不会影响鸿蒙项目的开发。

安装鸿蒙依赖包并生成bundle

版本信息

本节中使用的各类文件的版本配套关系,可以参考 React Native For OpenHarmony 版本信息

快速开始 : 您也可以直接使用 docs/Zips/AwesomeProjectReplace 文件夹 中的对应文件进行一一替换,修改版本信息并运行。

1. 修改 package.json

打开 AwesomeDemo 目录下的 package.json,在 scripts 下新增 OpenHarmony 的依赖:

json 复制代码
{
  "name": "AwesomeDemo",
  "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",
    "dev": "react-native bundle-harmony --dev"
  },
  "dependencies": {
    "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"
  }
}

2. 安装鸿蒙依赖包

AwesomeProject 目录下运行安装依赖包命令:

复制代码
npm install @react-native-oh/react-native-harmony@0.72.108

注意 : 如果要使用 Codegen,请在此处配置 Codegen 相关命令,详细请参考 Codegen

3. 配置 Metro

打开 AwesomeProject/metro.config.js,并添加 OpenHarmony 的适配代码:

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

/**
* @type {import("metro-config").ConfigT}
*/
const config = {
  transformer: {
    getTransformOptions: async () => ({
      transform: {
        experimentalImportSupport: false,
        inlineRequires: true,
      },
    }),
  },
};

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

参考 : 配置文件的详细介绍,可以参考 React Native 中文网

4. 生成 Bundle 文件

AwesomeProject 目录下运行生成 bundle 文件的命令:

bash 复制代码
npm run dev

运行成功后,会在 AwesomeProject/harmony/entry/src/main/resources/rawfile 目录下生成:

  • bundle.harmony.js - 主要的 JavaScript bundle 文件
  • assets 文件夹 - 存放图片资源(如果 bundle 中不涉及本地图片,则没有此文件夹)

预期输出示例:

复制代码
[INFO] Redirected imports from react-native to @react-native-oh/react-native-harmony
[INFO] No harmony-specific third-party packages have been detected
[CREATED] ./harmony/entry/src/main/resources/rawfile/bundle.harmony.js
info Copied 6 assets

创建鸿蒙工程

1. 创建新项目

在 DevEco Studio 中创建新的鸿蒙项目:

  1. 点击 File > New > Create Project
  2. 选择创建 Empty Ability 工程
  3. 点击 Next 按钮
  4. Compile SDK 中选择 API20
  5. 创建一个名为 "reactdemo" 的项目
  6. 注意项目路径不要太长

2. 配置签名

连接真机设备,配置项目签名:

  1. 点击 File > Project Structure
  2. 在弹窗界面点击 Signing Configs
  3. 勾选 Support HarmonyOSAutomatically generate signature
  4. 点击 Sign In 登录华为账号
  5. 完成签名配置

3.添加 React Native 配置

entry 目录下执行以下命令:

复制代码
ohpm i @rnoh/react-native-openharmony@0.72.108

在原生工程中集成RNOH

1. 配置 CPP 侧代码

创建 cpp 目录

MyApplication/entry/src/main 目录下新建 cpp 文件夹。

创建 CMakeLists.txt

cpp 目录下新增 CMakeLists.txt,将 RNOH 的适配层代码添加到编译构建中:

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) # for other CMakeLists.txt files to use

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)
创建 PackageProvider.cpp

cpp 目录下新增 PackageProvider.cpp,该文件需要满足以下要求:

  • 需要导入 RNOH/PackageProvider
  • 实现 getPackages 方法,用于创建三方库或自定义 TurboModule 或 Fabric 的 package 对象
cpp 复制代码
#include "RNOH/PackageProvider.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {};
}
配置 build-profile.json5

打开 MyApplication/entry/build-profile.json5,将 cpp 中的代码添加到应用工程的编译构建任务中:

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

注意 : 如果在 x86_64 架构的模拟器上运行应用,需在 externalNativeOptions 配置中额外添加 abiFilters 字段,并包含 x86_64 架构参数。默认仅构建适用于 arm64-v8a 架构的版本。
参考 : 详细介绍可以参考模块级build-profile.json5

2. 配置 ArkTS 侧代码

修改 EntryAbility.ets

打开 MyApplication/entry/src/main/ets/entryability/EntryAbility.ets,引入并使用 RNAbility

typescript 复制代码
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 {
  getPagePath() {
    return 'pages/Index';
  }

  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');
  }
}

重要要求:

  • 需要重写 getPagePath,返回程序的入口 page
  • 如果需要扩展使用对应的生命周期函数:
    • 请在代码中调用 super(由于 RNAbility 在生命周期函数中进行了对应的操作,因此建议使用 super 以确保原有功能不丢失)
    • 需确保函数的参数列表与父类保持兼容
    • 建议添加 override 关键字,以提升代码可读性并增强编译器检查

扩展示例:

typescript 复制代码
import { RNAbility } from '@rnoh/react-native-openharmony';

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

  override onCreate(want: Want): void {
    super.onCreate(want);
    hilog.info(0x0000, 'testTag', '%{public}s', 'EntryAbility onCreate');
  }
}
创建 RNPackagesFactory.ets

MyApplication/entry/src/main/ets 目录下新增 RNPackagesFactory.ets

typescript 复制代码
import { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony/ts';

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

要求:

  • @rnoh/react-native-openharmony 导入 RNPackageContextRNPackage
  • 在文件中导出 createRNPackages 方法,用于创建三方库或自定义 TurboModule、Fabric 的 package 对象
  • 此处不涉及三方库与自定义 TurboModule 或组件,需要返回空数组
修改 Index.ets

打开 MyApplication/entry/src/main/ets/pages/Index.ets,添加 RNOH 的使用代码:

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")
    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: "AwesomeDemo", // 尤其要注意,这个是你的rn的项目的名称
          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%')
  }
}

重要 : RNApp 的参数 appKey 需要与 RN 工程中 AppRegistry.registerComponent 注册的 appName 保持一致,否则会导致白屏。

加载bundle包

在上一章节中已经完成了 bundle 文件的生成,接下来将它加载到 DevEco Studio 中以运行 MyApplication 项目。

1. 拷贝 Bundle 文件

将 RN 侧的 rawfile 文件拷贝到鸿蒙侧的 rawfile 目录:

  • 源路径:AwesomeProject/harmony/entry/src/main/resources/rawfile/
  • 目标路径:MyApplication/entry/src/main/resources/rawfile/

2. 运行项目

连接设备

用数据线将真机与电脑连接,打开新的命令行工具并执行:

bash 复制代码
hdc rport tcp:8081 tcp:8081
启动 Metro 服务器

RN 工程目录中执行以下命令启动 RN 应用:

bash 复制代码
npm run start

预期输出:

复制代码
Metro waiting on exp://192.168.x.x:8081
Scan the QR code above with Expo Go (Android) or the Camera app (iOS)
运行鸿蒙应用

在 DevEco Studio 中点击运行按钮,选择连接的设备运行应用。

相关阅读

常见问题

1. 环境变量问题

问题 : 环境变量设置后不生效
解决方案:

  • 确保在正确的 shell 配置文件中添加环境变量
  • 执行 source ~/.zshrcsource ~/.bash_profile 使配置生效
  • 重新打开终端验证环境变量

2. Bundle 生成失败

问题 : npm run dev 命令执行失败
解决方案:

  • 检查 Node.js 版本是否为 16 或更高
  • 确保已正确安装 @react-native-oh/react-native-harmony 依赖
  • 检查 metro.config.js 配置是否正确

3. 应用白屏

问题 : 鸿蒙应用启动后显示白屏
解决方案:

  • 检查 appKey 是否与 RN 工程中的 AppRegistry.registerComponent 注册的 appName 一致
  • 确保 bundle 文件已正确拷贝到鸿蒙项目的 rawfile 目录
  • 检查设备连接和端口转发是否正常

4. 依赖安装问题

问题 : npm 安装依赖失败或速度慢
解决方案:

  • 使用国内镜像源:npm config set registry https://repo.huaweicloud.com/repository/npm/
  • 清除 npm 缓存:npm cache clean --force
  • 使用 yarn 替代 npm:yarn install

5. 编译错误

问题 : 鸿蒙项目编译失败
解决方案:

  • 检查 OpenHarmony SDK 版本是否为 API 20
  • 确保 DevEco Studio 版本为最新
  • 检查 build-profile.json5 配置是否正确
  • 清理项目后重新编译:Build > Clean Project

尤其关注这个仓库:https://atomgit.com/openharmony-sig/ohos_react_native/tree/master/docs/Zips

相关推荐
2501_948122632 小时前
React Native for OpenHarmony 实战:Steam 资讯 App 设置页面
javascript·react native·react.js·游戏·ecmascript·harmonyos
奔跑的露西ly2 小时前
【HarmonyOS NEXT】Stage模型应用载体Want
华为·harmonyos
小雨下雨的雨2 小时前
Flutter鸿蒙共赢——秩序的巅峰:室利耶antra 与神圣几何的数字重构
flutter·重构·harmonyos
2501_948122632 小时前
React Native for OpenHarmony 实战:Steam 资讯 App 意见反馈实现
javascript·react native·react.js·游戏·ecmascript·harmonyos
小雨下雨的雨2 小时前
Flutter鸿蒙共赢——色彩的流变:流体梯度网格与现代视觉重构
算法·flutter·华为·重构·交互·harmonyos·鸿蒙
2501_944521002 小时前
rn_for_openharmony商城项目app实战-账号安全实现
javascript·数据库·安全·react native·react.js·ecmascript
Amumu121382 小时前
React路由(三)
javascript·react.js·ecmascript
小雨下雨的雨2 小时前
Flutter鸿蒙共赢——逻辑的繁花:初等元胞自动机与 Rule 7 的矩阵美学
线性代数·flutter·华为·矩阵·交互·harmonyos·鸿蒙系统
特立独行的猫a2 小时前
鸿蒙PC生态三方软件移植:ohos-sdk 生成的库或二进制的自动签名实现
华为·harmonyos·签名·ohos-sdk