鸿蒙rn项目搭建运行
先甩官方文档地址:gitee.com/openharmony…
步骤:
- 搭建一个rn项目
npx react-native@0.72.5 init AwesomeProject --version 0.72.5 - 安装鸿蒙依赖,将项目打包为bundle包
// 1.在项目的package.json文件的scripts里面添加运行命令 scripts:{ ... "dev": "react-native bundle-harmony --dev" ... } // 2. 安装鸿蒙依赖 npm i @react-native-oh/react-native-harmony@x.x.x // 3. 运行npm run dev 根目录会多出一个harmony文件夹 harmony\entry\src\main\resources\rawfile 问价夹下会有打包好的bundle文件和assets资源目录 - 搭建鸿蒙工程(没啥特别的)
- 添加rn配置(在entry下打开终端运行)
ohpm i @rnoh/react-native-openharmony@x.x.x - 补充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)
-
在 cpp 目录下新增
PackageProvider.cpp,该文件需要满足以下要求:-
需要导入
RNOH/PackageProvider; -
实现
getPackages方法,用于创建三方库或自定义 TurboModule 或 Fabric 的 package 对象。
此处不涉及三方库与自定义 TurboModule 或组件,需要返回空数组。
#include "RNOH/PackageProvider.h" using namespace rnoh; std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) { return {}; } -
-
打开
MyApplicaton\entry\build-profile.json5,将 cpp 中的代码添加到鸿蒙的编译构建任务中,详细介绍可以参考模块级build-profile.json5:{ "apiType": "stageMode", "buildOption": { + "externalNativeOptions": { + "path": "./src/main/cpp/CMakeLists.txt", + "arguments": "", + "cppFlags": "", + } }, "buildOptionSet": [ { "name": "release", "arkOptions": { "obfuscation": { "ruleOptions": { "enable": true, "files": [ "./obfuscation-rules.txt" ] } } } }, ], "targets": [ { "name": "default" }, { "name": "ohosTest", } ] }
充ArkTS侧的代码
-
打开
MyApplicaton\entry\src\main\ets\entryability\EntryAbility.ets,引入并使用RNAbility,该文件需要满足以下的要求:- 如果需要扩展使用对应的生命周期函数,请在代码中使用 super,
RNAbility在生命周期函数中进行了对应的操作,需要使用 super 保证功能不丢失; - 需要重写
getPagePath,返回程序的入口 page。
import { RNAbility } from '@rnoh/react-native-openharmony'; export default class EntryAbility extends RNAbility { getPagePath() { return 'pages/Index'; } } - 如果需要扩展使用对应的生命周期函数,请在代码中使用 super,
-
在
MyApplicaton\entry\src\main\ets目录下新增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 []; } -
-
打开
MyApplicaton\entry\src\main\ets\pages\Index.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<string, string>, 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 HarmonyOS 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包
在上一章节中已经完成了 bundle 文件的生成,接下来将它加载到 DevEco Studio 中以运行 MyApplication 项目。加载 bundle 有三种方式:
-
方式一:本地加载 bundle。将 bundle 文件和 assets 图片放在
entry/src/main/resources/rawfile路径下,在entry/src/main/ets/pages/Index.ets中使用。 -
方式二:使用 Metro 服务加载 bundle。详细流程参考Metro热加载。
-
方式三:加载沙箱目录的bundle:
-
应用沙箱是一种以安全防护为目的的隔离机制,避免数据受到恶意路径穿越访问。在这种沙箱的保护机制下,应用可见的目录范围即为“应用沙箱目录”。
-
开发者在应用开发调试时,需要向应用沙箱下推送一些文件以期望在应用内访问或测试,此时有两种方式:
− 第一种:可以通过 DevEco Studio 向应用安装路径中放入目标文件,详见应用安装资源访问。
− 第二种:在具备设备环境时,可以使用另一种更为灵活的方式,通过 hdc 工具来向设备中应用沙箱路径推送文件。推送命令如下,其中,沙箱路径可通过向应用沙箱推送文件查询:
hdc file send ${待推送文件的本地路径} ${沙箱路径} -
加载沙箱目录 bundle,需要在 RNApp 的
jsBundlePrivider参数中使用new FileJSBundleProvider('bundlePath')将 bundle 注册进框架,并运行 bundle。
-
在 MyApplication/entry 目录下 Index.ets 文件中,创建 RNApp 时传入 jsBundleProvider 用于加载 bundle。如下所示这里传入了 FileJSBundleProvider,用于沙箱目录加载 bundle。
然后运行就行了运行报错的话在entry下的build-profile.json5文件下添加
"buildOption": {
"externalNativeOptions": {
"path": "./src/main/cpp/CMakeLists.txt",
"arguments": "",
"cppFlags": "",
+ "abiFilters": [
+ "arm64-v8a",
+ "x86_64"
+ ]
}
},