ReactNative鸿蒙化从基础到应用
准备:
下载node.js:Node.js — 在任何地方运行 JavaScript
下载完成后一直点下一步继续安装完成。
安装完成后,在终端输入:node -v 查看node版本
npm -v 查看npm版本
下载安装React Native:搭建开发环境 · React Native 中文网
在终端输入:npm install -g expo-cli
安装DevEco Studio,其中DevEco Studio的api版本要大于13
文档中心https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-software-install-V5
环境配置:
官方文档地址:GitCode - 全球开发者的开源社区,开源代码托管平台
windows 环境变量设置方法:
hdc环境配置
hdc 是 OpenHarmony 为开发人员提供的用于调试的命令行工具,鸿蒙 React Native 工程使用 hdc 进行真机调试。hdc 工具通过 OpenHarmony SDK 获取,存放于 SDK 的 toolchains
目录下,请将 {DevEco Studio安装路径}/sdk/{SDK版本}/openharmony/toolchains
的完整路径添加到环境变量中。
a. 在此电脑 > 属性 > 高级系统设置 > 高级 > 环境变量中,编辑系统变量path,添加hdc工具路径。
b. 在此电脑 > 属性 > 高级系统设置 > 高级 > 环境变量中,添加 HDC 端口变量名为:HDC_SERVER_PORT
,变量值可设置为任意未被占用的端口,如 7035
。
安装an zan文档中心配置 CAPI 版本环境变量
当前RN框架提供的 Demo 工程默认为 CAPI 版本,您需要配置环境变量 RNOH_C_API_ARCH = 1
。
-
Windows 环境:
在此电脑 > 属性 > 高级系统设置 > 高级 > 环境变量中,在系统变量中点击新建,添加变量名为:
RNOH_C_API_ARCH
,变量值为1
。 -
Mac环境配置:
终端输入:open ~/.zshrc
如果没有.zshrc文件,输入vim ~/.zshrc 创建环境配置文件。
创建新项目React Native侧:
终端输入:npx react-native@0.72.5 init AwesomeProject --version 0.72.5 --skip-install
打开工程的package.json文件,在 scripts
下新增 OpenHarmony 的依赖
终端进入AwesomeProject目录,并运行安装依赖包命令:npm i @react-native-oh/react-native-harmony@0.72.53
安装完成:
1.打开 AwsomeProjectmetro.config.js
,并添加 OpenHarmony 的适配代码。配置文件的详细介绍,可以参考React Native 中文网。修改完成后的文件内容如下:
全部删掉,替换成:
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);
2.在 AwesomeProject 目录下运行生成 bundle 文件的命令。运行成功后,会在 AwesomeProject/harmony/entry/src/main/resources/rawfile
目录下生成 bundle.harmony.js
和 assets
文件夹,assets
用来存放图片(如果 bundle
中不涉及本地图片,则没有 assets
文件夹)。
在RN的终端输入:npm run dev
鸿蒙侧:
只支持api13的工程项目:
创建完成后,进入entry目录的终端:
终端输入:ohpm i @rnoh/react-native-openharmony@0.72.53
在原生工程中集成RNOH
1.补充CPP侧代码
- 在
MyApplication/entry/src/main
目录下新建 cpp 文件夹。 - 在 cpp 目录下新增
CMakeLists.txt
,并将 RNOH 的适配层代码添加到编译构建中生成librnoh_app.so
:
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)
2.在 cpp 目录下新增 PackageProvider.cpp
,该文件需要满足以下要求:
- 需要导入
RNOH/PackageProvider
; - 实现
getPackages
方法,用于创建三方库或自定义 TurboModule 或 Fabric 的 package 对象。
此处不涉及三方库与自定义 TurboModule 或组件,需要返回空数组。
#include "RNOH/PackageProvider.h"
using namespace rnoh;
std::vector> PackageProvider::getPackages(Package::Context ctx) {
return {};
}
3.打开 MyApplicatonentryuild-profile.json5
,将 cpp 中的代码添加到鸿蒙的编译构建任务中,详细介绍可以参考模块级build-profile.json5:
"buildOption": {
"externalNativeOptions": {
"path": "./src/main/cpp/CMakeLists.txt",
"arguments": "",
"cppFlags": "",
}
},
补充ArkTS侧的代码
- 打开
MyApplicatonentrysrcmainetsentryabilityEntryAbility.ets
,引入并使用RNAbility
,该文件需要满足以下的要求:- 如果需要扩展使用对应的生命周期函数,请在代码中使用 super,
RNAbility
在生命周期函数中进行了对应的操作,需要使用 super 保证功能不丢失; - 需要重写
getPagePath
,返回程序的入口 page。
- 如果需要扩展使用对应的生命周期函数,请在代码中使用 super,
import { RNAbility } from '@rnoh/react-native-openharmony';
export default class EntryAbility extends RNAbility {
getPagePath() {
return 'pages/Index';
}
}
2.在 MyApplicatonentrysrcmainets
目录下新增 RNPackagesFactory.ets
,该文件需要满足以下要求:
- 在
@rnoh/react-native-openharmony
导入RNPackageContext
和RNPackage
; - 在文件中导出
createRNPackages
方法,用于创建三方库或自定义 TurboModule、Fabric的package 对象。
此处不涉及三方库与自定义TurboModule或组件,需要返回空数组。
import { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony/ts';
export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
return [];
}
3.打开 MyApplicatonentrysrcmainetspagesIndex.ets
,添加RNOH的使用代码,修改后如下:
RNApp
的参数appKey
需要与RN工程中AppRegistry.registerComponent
注册的appName
保持一致,否则会导致白屏。
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,
appKey: "AwesomeProject",
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%')
}
}
最后:加载bundle包
将RN侧的rawfile文件拷贝到鸿蒙侧的rawfile
鸿蒙侧运行:
热更新:
认识React Native
React Native 是由 Facebook 开发的一个开源框架,用于构建原生移动应用。它结合了 React 的声明式编程范式和 JavaScript 的灵活性,允许开发者使用相同的代码库为 iOS 和 Android 平台创建高性能、美观且用户体验良好的应用。
总之,React Native 是一个强大的跨平台移动应用开发框架,适合各种规模和类型的项目。如果你想快速开发高性能的移动应用,React Native 是一个不错的选择。