鸿蒙开发harmonyos集成react native

上一篇文章说下载鸿蒙开发工具,今天开始实践了

1. 新建rn项目(mac端)

npx react-native@0.72.5 init AwesomeProject --version 0.72.5

或者使用如下命令,跳过其他node_modules的安装过程,因为暂时不需要依赖库,但是网速好的情况下,还是建议用上面的命令,一次安装成功

npx react-native@0.72.5 init AwesomeProject --version 0.72.5 --skip-install

init之后的文件夹如图所示,这里只有ios和android文件夹,我的理解应该有个harmony文件夹放着鸿蒙的项目才对,让我们接着往下看


image.png

2.下载安装鸿蒙依赖

在react native项目的package.json文件内添加"dev": "react-native bundle-harmony --dev"这句话

{
 "name": "AwesomeProject",
 "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"
 }
}

打开terminal,cd到新建项目的文件下,执行

// @x.x.x可以不要,默认会安装最新版的依赖,也可以指定版本号,但是要考虑跟rn版本的兼容性
npm i @react-native-oh/react-native-harmony@x.x.x
// 我这里用的是npm i @react-native-oh/react-native-harmony@0.72.53

3. 修改rn配置文件metro.config.js

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

4. 生成bundle文件,供鸿蒙使用

cd到rn对应的文件夹下,运行npm run dev 即运行npm run react-native bundle-harmony --dev
运行完成会生成bundle.harmony.js和assets文件夹,如下图

131751370932_.pic.jpg

5. 新建鸿蒙项目

这里不再过多介绍,鸿蒙开发官网都有介绍,注意一点:在创建项目的时候,bundlename要与开发者证书里的bundlename一致,可以在DevEco Studio -> file -> project structure中查看bundle name,如下图

image.png

然后在确定下证书中对应的bundle name,终端输入命令:keytool -list -v -keystore debug2.p12 -storetype PKCS12
image.png

我这里随便找的一个证书实验的,所以bundle name是空,bundle name是所有者: CN=test5566, OU=, O=, L=, ST=, C=中的O=对应的东西。

6,修改bundle name(非必需)

找到AppScope/app.json5

{
  "app": {
    "bundleName": "com.123.app.id",
    "vendor": "example",
    "versionCode": 1000000,
    "versionName": "1.0.0",
    "icon": "$media:app_layered_image",
    "label": "$string:app_name"
  }
}

在这里修改之后,build clean,然后rebuild即可

7,在 MyApplication/entry/src/main 目录下新建 cpp 文件夹。在 cpp 目录下新增 CMakeLists.txt

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)

8,在 cpp 目录下新增 PackageProvider.cpp

#include "RNOH/PackageProvider.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {};
}

9,打开 MyApplicaton\entry\build-profile.json5,将 cpp 中的代码添加到鸿蒙的编译构建任务中

{
 "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",
   }
 ]
}

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

import { RNAbility } from '@rnoh/react-native-openharmony';

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

11, 在 MyApplicaton\entry\src\main\ets 目录下新增 RNPackagesFactory.et

import { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony/ts';
export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [];
}

12,打开 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%')
  }
}

13,加载bundle包,本地加载 bundle。将 bundle 文件和 assets 图片放在 entry/src/main/resources/rawfile 路径下,在 entry/src/main/ets/pages/Index.ets 中使用

最后一步,运行鸿蒙,一定要连接手机,不然会报错

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容