鸿蒙RN三方库使用AutoLinking

一、创建三方库工程

mkdir ~/react_native/example/rn-lib-math
cd ~/react_native/example/rn-lib-math
npm init .

初始化后得到一个基本的package.json文件,然后修改内容为:

{
  "name": "rn-lib-math",
  "version": "1.0.0",
  "description": "rn lib math package of autolinking in harmony",
  "main": "index.ts",
  "scripts": {
    "codegen-lib": "react-native codegen-lib-harmony --no-safety-check --npm-package-name rn-lib-math --cpp-output-path ./harmony/library/src/main/cpp/generated --ets-output-path ./harmony/library/src/main/ets/generated --cpp-components-spec-paths ./src/specs/cpp-components --turbo-modules-spec-paths ./src/specs/turbo-modules --arkts-components-spec-paths ./src/specs/arkts-components"
  },
  "author": "",
  "license": "ISC",
  "harmony": {
    "alias": "rn-lib-math",
    "autolinking": {
      "cmakeLibraryTargetName": "rn_lib_math"
    }
  },
  "files": [
    "index.ts",
    "src/*",
    "harmony/*"
  ],
  "dependencies": {},
  "devDependencies": {
    "@react-native-community/cli": "15.0.1",
    "@react-native-oh/react-native-harmony": "^0.77.18",
    "@react-native-oh/react-native-harmony-cli": "^0.77.18",
    "@types/react": "^18.3.1",
    "react": "18.3.1",
    "react-native": "0.77.1"
  }
}

写好package.json后 安装依赖,会产生node_modules目录

npm i —verbose

这里主要是

scripts里面的 codegen-lib配置

codegen-lib-harmony 跟codegen-harmony类似,只不过这里是针对lib库的代码生成,里面有几个路径要配置下
--npm-package-name rn-lib-math
--cpp-output-path ./harmony/library/src/main/cpp/generated
--ets-output-path ./harmony/library/src/main/ets/generated
--cpp-components-spec-paths ./src/specs/cpp-components
--turbo-modules-spec-paths ./src/specs/turbo-modules
--arkts-components-spec-paths ./src/specs/arkts-components

harmony配置

 "harmony": {
    "alias": "rn-lib-math",
    "autolinking": {
      "cmakeLibraryTargetName": "rn_lib_math"
    }
  },

files配置

"files": [
    "index.ts",
    "src/*",
    "harmony/*"
  ],

devDependencies配置

"devDependencies": {
    "@react-native-community/cli": "15.0.1",
    "@react-native-oh/react-native-harmony": "^0.77.18",
    "@react-native-oh/react-native-harmony-cli": "^0.77.18",
    "@types/react": "^18.3.1",
    "react": "18.3.1",
    "react-native": "0.77.1"
  }

创建TurboModule描述文件,arkts-components、cpp-components这两个目录先为空
src/specs/turbo-modules/MathModule.ts

import { TurboModule, TurboModuleRegistry } from "react-native";

export interface Spec extends TurboModule {
  add(a: number, b: number): Promise<number>;
  subtract(a: number, b: number): Promise<number>;
  multiply(a: number, b: number): Promise<number>;
  divide(a: number, b: number): Promise<number>;
}
export default TurboModuleRegistry.get<Spec>("MathModule");

二、创建harmony工程

用DevEco Studio 在当前路径下创建一个harmony工程,默认带一个entry模块,并且在harmony工程创建一个library模块(Static Library)

整体目录结构为,我们只需要用到里面library库

fangzhen@Mac rn-lib-math % tree -L 3 --gitignore
.
├── harmony
│   ├── AppScope
│   │   ├── app.json5
│   │   └── resources
│   ├── build-profile.json5
│   ├── code-linter.json5
│   ├── entry
│   │   ├── build-profile.json5
│   │   ├── hvigorfile.ts
│   │   ├── obfuscation-rules.txt
│   │   ├── oh-package-lock.json5
│   │   ├── oh-package.json5
│   │   └── src
│   ├── hvigor
│   │   └── hvigor-config.json5
│   ├── hvigorfile.ts
│   ├── library
│   │   ├── BuildProfile.ets
│   │   ├── Index.ets
│   │   ├── build-profile.json5
│   │   ├── consumer-rules.txt
│   │   ├── hvigorfile.ts
│   │   ├── obfuscation-rules.txt
│   │   ├── oh-package-lock.json5
│   │   ├── oh-package.json5
│   │   └── src
│   ├── library.har
│   ├── oh-package-lock.json5
│   └── oh-package.json5
├── index.ts
├── package.json
└── src
    └── specs
        ├── arkts-components
        ├── cpp-components
        └── turbo-modules

14 directories, 23 files

rn-lib-math/harmony/build-profile.json5 配置修改

"useNormalizedOHMUrl": false

这里不修改library编译出的har包里面没有其他资源文件,包括cpp目录

rn-lib-math/harmony/oh-package.json5 里面配置react-native-harmony.har 这个在npm i后会安装到本地

"dependencies": {
  "@rnoh/react-native-openharmony": "file:../node_modules/@react-native-oh/react-native-harmony/react_native_openharmony.har"
},
"overrides": {
  "@rnoh/react-native-openharmony": "file:../node_modules/@react-native-oh/react-native-harmony/react_native_openharmony.har"
}

rn-lib-math/harmony/library/oh-package.json5 里配置name 和 react_native_openharmony.har依赖

{
  "name": "@rnoh/rn-lib-math",
  "version": "1.0.0",
  "description": "Please describe the basic information.",
  "main": "Index.ets",
  "author": "",
  "license": "Apache-2.0",
  "dependencies": {
    "@rnoh/react-native-openharmony": "file:../../node_modules/@react-native-oh/react-native-harmony/react_native_openharmony.har"
  }
}

harmony/entry/build-profile.json5 添加react-native-openharmony.har依赖,这个entry工程不过是为了调试

"dependencies": {
    "@rnoh/react-native-openharmony": "file:../../node_modules/@react-native-oh/react-native-harmony/react_native_openharmony.har",
    "@rnoh/rn-lib-math": "file:../library"
  }

harmony/entry/build-profile.json5 添加externalNativeOptions配置

 "buildOption": {
    "externalNativeOptions": {
      "path": "./src/main/cpp/CMakeLists.txt",
      "arguments": "",
      "cppFlags": "",
    },
    "resOptions": {
      "copyCodeResource": {
        "enable": false
      }
    }
  },

harmony/entry/src/main/cpp/CMakeLists.txt

project(rnapp)
cmake_minimum_required(VERSION 3.5)
set(OH_MODULES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(RNOH_GENERATED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/generated")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules/@rnoh/react-native-openharmony/src/main/cpp")
set(WITH_HITRACE_SYSTRACE 1)
add_compile_definitions(WITH_HITRACE_SYSTRACE)

add_subdirectory("${RNOH_CPP_DIR}" ./rn)
add_subdirectory("${OH_MODULES_DIR}/@rnoh/rn-lib-math/src/main/cpp" ./rn-lib-math)
file(GLOB_RECURSE GENERATED_CPP_FILES "./generated/*.cpp")
file(GLOB package_src CONFIGURE_DEPENDS *.cpp)
add_library(rnoh_app SHARED
    ${GENERATED_CPP_FILES}
	${VISION_CAMERA_CPP_FILES}
    ${package_src}
    "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_link_libraries(rnoh_app PUBLIC rnoh)
target_link_libraries(rnoh_app PUBLIC rn-lib-math)

在package.json目录下运行。==npm run codeine-lib ==
生成cpp 和 arkts代码

三、 将生成的代码通过api 提供

harmony/library/src/main/cpp/CMakeLists.txt

cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)

set(rn_lib_math_generated_dir "${CMAKE_CURRENT_SOURCE_DIR}/generated")
file(GLOB_RECURSE rn_lib_math_generated_SRC "${rn_lib_math_generated_dir}/**/*.cpp")
file(GLOB rn_lib_math_SRC CONFIGURE_DEPENDS *.cpp)
add_library(rn_lib_math SHARED ${rn_lib_math_generated_SRC} ${rn_lib_math_SRC} RnLibMathPackage.h RnLibMathPackage.cpp)
target_include_directories(rn_lib_math PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${rn_lib_math_generated_dir})
target_link_libraries(rn_lib_math PUBLIC rnoh)

harmony/library/src/main/cpp/RnLibMathPackage.h

#ifndef HARMONY_MATHPACKAGE_H
#define HARMONY_MATHPACKAGE_H
#include "generated/RNOH/generated/BaseRnLibMathPackage.h"
namespace rnoh {

class RnLibMathPackage:public BaseRnLibMathPackage {
    using Super = BaseRnLibMathPackage;
public:
    explicit RnLibMathPackage(Package::Context ctx):BaseRnLibMathPackage(ctx){}
    
    ComponentInstance::Shared createComponentInstance(const ComponentInstance::Context& ctx) override ;
};
}

#endif //HARMONY_MATHPACKAGE_H

harmony/library/src/main/cpp/RnLibMathPackage.cpp

#include "RnLibMathPackage.h"
#include "RNOH/RNInstanceCAPI.h"
using namespace facebook;

namespace rnoh {
ComponentInstance::Shared RnLibMathPackage::createComponentInstance(const ComponentInstance::Context &ctx) {
    return nullptr;
}
} // namespace rnoh

harmony/library/src/main/ets/RnLibMathModule.ets

import { EtsUITurboModule } from "@rnoh/react-native-openharmony";
import { TM } from "./generated/ts";

export class RnLibMathModule extends EtsUITurboModule implements TM.MathModule.Spec{
  add(a: number, b: number): Promise<number> {
    return Promise.resolve(a+b)
  }

  subtract(a: number, b: number): Promise<number> {
    return Promise.resolve(a-b)
  }

  multiply(a: number, b: number): Promise<number> {
    return Promise.resolve(a*b)
  }

  divide(a: number, b: number): Promise<number> {
    return Promise.resolve(a/b)
  }

}

harmony/library/src/main/ets/RnLibMathPackage.ets

import { RNOHPackage, UITurboModule, UITurboModuleContext } from "@rnoh/react-native-openharmony";
import { TM } from "./generated/ts";
import { RnLibMathModule } from "./RnLibMathModule";

export class RnLibMathPackage extends RNOHPackage {
  getUITurboModuleFactoryByNameMap(): Map<string, (ctx: UITurboModuleContext) => UITurboModule | null> {
    return new Map([
      [TM.MathModule.NAME, (ctx) => new RnLibMathModule(ctx)]
    ])
  }
}

编译harmony/library模块
生成har包位置在harmony/library/build/default/outputs/default/library.har
将har包拷贝到harmony 目录下

在package.json目录下运行 ==npm pack ==
将在根目录下生成 rn-lib-math-1.0.0.tgz文件

四、RNOH项目运行三方库

Package.json添加依赖,或者通过npm 命令指定路径安装这个tgz文件

"dependencies": {
    "@react-native-oh/react-native-harmony": "^0.77.18-1",
    "react": "18.3.1",
    "react-native": "0.77.1",
    "third-party-library": "file:../third-party-library/third-party-library-1.0.0.tgz",
    "rn-lib-math": "file:../rn-lib-math/rn-lib-math-1.0.0.tgz"
  },

npm i —verbose
安装完成后通过deveco studio 打开RNOH的harmony工程
harmony/hvigor/hvigor-config.json5添加插件依赖,只用添加一次,后面再集成其他rn三方库不用再配置

 "dependencies": {
    "@rnoh/hvigor-plugin": "file:../../node_modules/@react-native-oh/react-native-harmony-cli/harmony/rnoh-hvigor-plugin-0.77.22.tgz"
  },

harmony/entry/hvigorfile.ts 文件改动

import { hapTasks } from '@ohos/hvigor-ohos-plugin';
//
// export default {
//   system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
//   plugins: []       /* Custom plugin to extend the functionality of Hvigor. */
// }

import { createRNOHModulePlugin } from "@rnoh/hvigor-plugin"

export default {
  system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
  plugins: [
    createRNOHModulePlugin({
      nodeModulesPath: "../node_modules",
      codegen: null,
      autolinking: {}
    }),
  ]
}

同步工程后会生成这几个文件

harmony/entry/src/main/ets/RNOHPackagesFactory.ets
harmony/entry/src/main/cpp/RNOHPackagesFactory.h
harmony/entry/src/main/cpp/autolinking.cmake

CMakeLists.txt添加

include("${CMAKE_CURRENT_SOURCE_DIR}/autolinking.cmake")
autolink_libraries(rnoh_app) # 这个放最后一行,这个函数就是在autolinking.cmake中定义的

原来PackageProvider.cpp 改动
harmony/entry/src/main/cpp/PackageProvider.cpp

#include "RNOH/PackageProvider.h"
//#include "RNOH/generated/BaseTurbomoduleDemoPackage.h"
#include "generated/RNOHGeneratedPackage.h"
#include "RNOHPackagesFactory.h"
using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    auto packages = createRNOHPackages(ctx); //这里把生成的三方库创建的packages添加进来,与当前工程定义的package合并
    packages.push_back(std::make_shared<RNOHGeneratedPackage>(ctx));//当前工程自己定义的Package
//    packages.push_back(std::make_shared<BaseTurbomoduleDemoPackage>(ctx));
    return packages;
}

harmony/entry/src/main/ets/RNPackagesFactory.ets

import {
  RNOHPackage, RNPackageContext, UITurboModule, UITurboModuleContext
} from "@rnoh/react-native-openharmony";
import { TM } from "@rnoh/react-native-openharmony/generated/index"
import { createRNOHPackages } from "./RNOHPackagesFactory";
import { CalcModule } from "./turbomodule/CalcModule";

class GeneratedPackage extends RNOHPackage {
  override getUITurboModuleFactoryByNameMap(): Map<string, (ctx: UITurboModuleContext) => UITurboModule | null> {
    return new Map([
      [TM.NativeCalc.NAME, (ctx) => new CalcModule(ctx)]
    ])
  }

  override async createEagerUITurboModuleByNameMap(ctx: UITurboModuleContext): Promise<Map<string, UITurboModule>> {
    return new Map([
      [TM.NativeCalc.NAME, new CalcModule(ctx)]
    ])
  }
}

export function createRNPackages(ctx: RNPackageContext): RNOHPackage[] {
  return [
    ...createRNOHPackages(ctx), //将三方库生成的packages添加进来
    new GeneratedPackage(ctx)//其他自定义package
  ]
}



后续再依赖其他三方库不需要改动,这三个文件中的内容会自动刷新依赖项

harmony/entry/src/main/ets/RNOHPackagesFactory.ets
harmony/entry/src/main/cpp/RNOHPackagesFactory.h
harmony/entry/src/main/cpp/autolinking.cmake

在App.tsx ui程序中可以使用

import {MathModule} from 'rn-lib-math';

let a = await MathModule?.divide(100, 200);

运行rn程序调试

npm run start
npm run ohos

这里运行的ohos是为了方便运行鸿蒙工程,不需要在deveco studio下去运行app
Ohos script为:

"scripts": {
    "ohos": "bash ohos.sh",
    "start": "hdc rport tcp:8081 tcp:8081 && react-native start",
    "codegen": "react-native codegen-harmony --cpp-output-path ./harmony/entry/src/main/cpp/generated --rnoh-module-path ./harmony/entry/oh_modules/@rnoh/react-native-openharmony",
    "dev": "npm run codegen && react-native bundle-harmony --dev",
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "lint": "eslint .",
    "test": "jest"
  },

ohos.sh内容,windows下可以翻译成bat脚本使用

#!/bin/bash
cd ./harmony && hvigorw --mode module -p module=entry@default -p product=default -p requiredDeviceType=phone assembleHap --analyze=normal --parallel --incremental --daemon
(/Applications/DevEco-Studio.app/Contents/tools/emulator/Emulator -hvd Huawei_Phone -path /Users/fangzhen/.Huawei/Emulator/deployed -imageRoot /Users/fangzhen/Library/Huawei/Sdk &)
echo "Waiting for the simulator to start..."
MAX_WAIT=60
WAITED=0
while [ $WAITED -lt $MAX_WAIT ]; do
    if hdc list targets 2>/dev/null | grep  -E "^127\.0\.0\.1:[0-9]+" | head -1; then
        echo "simulator is ready"
        break
    fi
    sleep 2
    WAITED=$((WAITED + 2))
    echo "Waiting for the simulator to start... ${WAITED} s"
done

if [ $WAITED -ge $MAX_WAIT ]; then
    echo "Error: Simulator launch timeout"
    exit 1
fi
hdc shell "aa force-stop com.rnoh.harmony"
hdc install "./entry/build/default/outputs/default/entry-default-unsigned.hap"
hdc shell "aa start -a EntryAbility -b com.rnoh.harmony"
exit

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐