创建鸿蒙工程

一、新建项目

        打开DevEco Studio,点击 File > New > Create Project,选择创建 Empty Ability 工程,如图所示:

        点击 Next 按钮,创建一个名为 “MyApplication” 的项目。如图所示:

二、新建模拟器(有真机的可以忽略这步用真机调试)

        点击右上角No devices,在在下拉列表中选择device manger

        点击下方模拟器保存路径进行配置,不建议放在C盘,因为会占用较大存储空间。配置完本地保存路径后,点击右侧New emulator进行新增模拟器。

        选择和新建项目sdk版本对应的phone模拟器,这里我用的sdk版本是HarmonyOS 6.0.2(22),因此我选择第一个,点击action下的下载按钮会开始下载模拟器镜像。

        请注意:如果在下载镜像期间报错说网络错误,DNS解析失败,这种情况一般是由于上次下载没有完全下载完毕就断开了导致的,需要清空模拟器路径中的所有文件,重启DevEco Studio重新加载即可。

        下载完毕后点击next,配置其他选项,也可以不改使用默认值。配置完毕后可以看到新建的这个模拟器,点击三角形按钮可以启动。

三、真机调试

        请注意,此次是官方文档说明,由于本人没有鸿蒙设备,没有经过验证。

        连接真机,点击 File > Project Structure,在弹窗界面点击 Signing Configs,勾选 Support HarmonyOS 和 Automatically generate signature,然后点击 Sign In 登录华为账号,并签名。

四、添加 React Native 配置

        在 entry 目录下执行以下命令:

ohpm i @rnoh/react-native-openharmony

        执行完成后会在工程级目录以及模块级目录下生成 oh_modules 文件夹。

        请注意:由于文件较大,下载时间可能比较长,请耐心等待。

五、补充CPP侧代码

  1. 在 MyApplication/entry/src/main 目录下新建 cpp 文件夹。
  2. 在 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)
    
  3. 在 cpp 目录下新增 PackageProvider.cpp,该文件需要满足以下要求:
    • 需要导入 RNOH/PackageProvider
    • 实现 getPackages 方法,用于创建三方库或自定义 TurboModule 或 Fabric 的 package 对象。
    #include "RNOH/PackageProvider.h"
    
    using namespace rnoh;
    
    std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
        return {};
    }
    
  4. 打开 MyApplicaton\entry\build-profile.json5,将 cpp 中的代码添加到应用工程的编译构建任务中;如果在 x86_64 架构的模拟器上运行应用,需在 externalNativeOptions 配置中额外添加 abiFilters 字段,并包含 x86_64 架构参数,如下所示,abiFilters 字段当前被注释,默认仅构建适用于 arm64-v8a 架构的版本。目前我使用的模拟器是无需这行配置。
    {
     "apiType": "stageMode",
     "buildOption": {
    +   "externalNativeOptions": {
    +      "path": "./src/main/cpp/CMakeLists.txt",
    +      "arguments": "",
    +      "cppFlags": "",
    +      // "abiFilters": ["arm64-v8a", "x86_64"]
    +    }
     },
     "targets": [
       {
         "name": "default"
       },
       {
         "name": "ohosTest",
       }
     ]
    }

六、补充ArkTS侧的代码

  1. 打开 MyApplicaton\entry\src\main\ets\entryability\EntryAbility.ets,引入并使用 RNAbility,该文件需要满足以下的要求:

    • 需要重写 getPagePath,返回程序的入口 page。
    import { RNAbility } from '@rnoh/react-native-openharmony';
    
    export default class EntryAbility extends RNAbility {
      getPagePath() {
        return 'pages/Index';
      }
    }
    
    • 如果需要扩展使用对应的生命周期函数
      • 请在代码中调用 super(由于 RNAbility 在生命周期函数中进行了对应的操作,因此建议使用 super 以确保原有功能不丢失)。
      • 需确保函数的参数列表与父类保持兼容。
      • 建议添加 override 关键字,以提升代码可读性并增强编译器检查。
    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');
      }
    }
    
  2. 在 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 [];
    }
    
  3. 打开 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 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 for OpenHarmony踩坑日记(二)https://blog.csdn.net/gaojw07/article/details/157292044中已经生成了bundle,此处只需要将其粘贴进入entry/src/main/resources/rawfile 路径下即可,并在 entry/src/main/ets/pages/Index.ets 中使用。

八、启动并运行工程

        启动模拟器,然后点击右上角启动按钮即可启动工程。

        错误:

16:41:54.307: Build task in 1 min 30 s 229 ms
16:41:54.309: Launching com.example.myapplication
16:41:54.312: $ hdc shell aa force-stop com.example.myapplication
16:41:54.578: $ hdc shell mkdir data/local/tmp/243d1319bd334876babe313110e563b7
16:41:55.315: $ hdc file send C:\Users\13650\DevEcoStudioProjects\MyApplication\entry\build\default\outputs\default\entry-default-signed.hap "data/local/tmp/243d1319bd334876babe313110e563b7" in 737 ms
16:41:55.711: $ hdc shell bm install -p data/local/tmp/243d1319bd334876babe313110e563b7 in 395 ms
Install Failed: error: failed to install bundle.
code:9568332
error: install sign info inconsistent.
View detailed instructions.
You can also uninstall and reinstall the modules.
16:41:55.820: $ hdc shell rm -rf data/local/tmp/243d1319bd334876babe313110e563b7
16:41:55.823: Launch com.example.myapplication failed, starting handle failure progress
Error while Deploy Hap

        错误原因:

        该问题是由于设备上已安装的应用与新安装的应用中签名不一致。如果在Run->Edit Configurations中勾选了“Keep Application Data”(不卸载应用,覆盖安装),并且重新进行了签名,将导致该报错。

        解决方案:

请卸载设备上已安装的应用,或取消勾选“Keep Application Data”后,重新安装新的应用。

        解决后启动成功。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐