开发工具: 华为云码道

本文配套仓库: oh-react-native/react-native-sha256

上游仓库: itinance/react-native-sha256

react-native-sha256 将 SHA-1 和 SHA-256 原生摘要计算封装为 React Native 接口,支持 UTF-8 字符串和字节数组输入。本文以 @react-native-ohos/react-native-sha256 1.4.10-0.0.1 为例,介绍源码准备、OHOS 工程配置、原生实现和 example 设备运行。

本适配保留上游 Android/iOS 实现,新增鸿蒙支持。源码位于 AtomGit 配套仓库,文中的代码以提交 27d87ed3e0221ca72284644a685aec17815ca501 为参考。配套仓库包含对应的鸿蒙实现和示例工程,文章中的版本、接口与运行结果以该仓库为准。


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

给初学者的阅读提示:
本文会同时出现四个目录或产物:插件仓库是源码所在的位置,example/ 是用来演示插件的应用,HAR 是插件的鸿蒙原生模块包,HAP 是最终安装到手机上的应用包。除非特别说明,命令都在插件仓库根目录执行。

可以先记住几个名词:RNOH 是 React Native 连接鸿蒙的运行层,ArkTS 是鸿蒙原生代码使用的语言,TurboModule 是 React Native 调用原生能力的一种模块,Metro 是把 JS/TS 打包成应用资源的工具。调用链是:React Native 页面调用 JS/TS 接口,RNOH 把调用转给 ArkTS 原生模块,ArkTS 再调用 HarmonyOS 系统能力,结果沿原路返回页面。

一、插件简介与适配目标

摘要把输入映射为固定长度的十六进制字符串,可用于数据一致性比对和已有协议需要的摘要字段。它是单向哈希,不是可以解密恢复明文的加密接口。

虽然库名包含 sha256,公开接口同时保留 SHA-1、SHA-256 及两种字节数组方法,文章和示例应覆盖全部四个入口。

sha1/sha256 接受字符串并按 UTF-8 编码,分别返回 40/64 位小写十六进制 Promise。sha1Bytes/sha256Bytes 接受 number[]。每次调用独立创建摘要实例,支持并发;没有监听、权限或释放接口。


二、环境准备

环境搭建参考社区文档:React Native OpenHarmony 环境初始化,完成 Node、对应 RN/RNOH 依赖、环境变量和 DevEco Studio 配置;框架能力与版本关系见 ohos_react_native。框架版本按下表选择,不直接套用最新分支。

完成后,在宿主机终端执行以下命令,确认当前工具链,并能发现目标设备:

node --version
npm --version
hdc list targets

node --version 和 npm --version 用来确认 Node.js 与包管理器可用;hdc list targets 用来确认电脑已经发现鸿蒙设备或模拟器。前两条命令只要能打印版本号即可,最后一条至少应出现一个设备 ID;如果列表为空,先处理 USB 调试授权或模拟器连接,再继续后面的构建。

工程使用的工具链和 SDK 配置如下:

项目版本或配置用途
Node.js24.12.0验证环境中的版本
React Native0.84.1鸿蒙宿主 RN 版本
React19.2.3与鸿蒙宿主配套
RNOH / Harmony CLI0.84.3JS 框架与鸿蒙 CLI
OHPM RNOH0.84.3原生运行时依赖
compileSdkVersion26.0.0编译 SDK
targetSdkVersion26.0.0应用目标行为版本
compatibleSdkVersion5.0.5(17)工程最低安装配置,不是最低设备实测结论
DevEco Studio26.0.0 Release(HarmonyOS SDK 26.0.0 / API 26)打开并构建 example/harmony 工程
适配包版本1.4.10-0.0.1package.json 中的交付版本
原生实现ArkTS / C++系统能力与 RNOH 桥接
插件产物harmony/sha256.har供宿主消费的 release HAR

鸿蒙工具依赖位于 example/harmony/package.json,与上游根目录及 Android/iOS 示例依赖分开。不要从旧示例的 RN 版本推断鸿蒙运行版本。

在这张表里,React Native 和 React 是页面使用的 JavaScript 层;RNOH 和 Harmony CLI 负责把这层代码接到鸿蒙工程;compileSdkVersion 是编译时使用的 API,targetSdkVersion 是应用面向的系统行为版本,compatibleSdkVersion 是工程声明的最低兼容版本。HAR 是插件交付包,HAP 是可以安装到设备上的应用包。

2.1 开发套件版本与工程中的 SDK 版本配置

26.0.0 是本工程 compile/target 字段值,对应编译 API 26;5.0.5(17) 声明最低兼容 API 17。SDK、IDE 版本和手机系统版本是不同信息。

对应 example/harmony/build-profile.json5 的 product 配置如下,合并到现有工程时保留其他产品和模块:

{
  "name": "default",
  "compileSdkVersion": "26.0.0",
  "compatibleSdkVersion": "5.0.5(17)",
  "runtimeOS": "HarmonyOS",
  "buildOption": {
    "strictMode": {
      "caseSensitiveCheck": true,
      "useNormalizedOHMUrl": true
    }
  },
  "targetSdkVersion": "26.0.0"
}

这组配置使用 API 26 SDK 编译,并以 API 26 为目标版本,最低兼容 API 17。安装后能否使用对应能力,还取决于设备系统和具体硬件,最低配置不代表对应版本设备已通过真机验证。


三、从源码仓库开始准备适配工程

3.1 将上游源码同步到 AtomGit

适配已有第三方插件时,先从 npm 包信息或项目 README 确认上游地址、包名、版本和许可证。同步仓库时保留源码、许可证和提交历史,方便后续跟踪上游更新。

本例上游为 react-native-sha256,基线版本 1.4.10,采用 MIT 许可证。当前配套仓库已经同步了适配结果;直接接入时无需再次导入上游。

需要继续维护时,在 AtomGit 网页的新建仓库流程中,找到从已有仓库导入的入口,填写上游 Git 地址,选择自己有写权限的组织或个人空间,设置目标仓库名称后执行导入。完成后检查目标分支、package.json、LICENSE 和提交历史是否完整,并记录适配起点的提交号。如果上游本身托管在 AtomGit,也可以通过 Fork 获得自己的工作仓库。

3.2 将代码拉取到宿主机

在安装了对应 RN/RNOH 工具链和 DevEco Studio 的开发电脑上打开终端,进入准备存放项目的目录,执行:

git clone https://atomgit.com/oh-react-native/react-native-sha256.git
cd react-native-sha256
pwd
ls
git remote -v
git status --short --branch
git rev-parse HEAD

git clone 会创建 react-native-sha256/ 目录;cd 后的位置就是下文所说的插件仓库根目录,这里应能看到 package.json、harmony/ 和 example/。Git 仓库名与 npm 包名 @react-native-ohos/react-native-sha256 不是同一标识。

需要使用与本文相同的代码版本时,在没有未提交修改的仓库中切换到以下提交:

git switch --detach 27d87ed3e0221ca72284644a685aec17815ca501

3.3 在仓库根目录创建适配分支

配套仓库的参考分支为 master。如果只是运行示例,保留固定提交即可;需要继续修改时,从该提交创建自己的工作分支。下面是建议的新分支名,不表示远端已经存在同名分支:

git switch -c feat/ohos_sha256_1.4.10-0.0.1
git branch --show-current

如果该分支已存在,使用 git switch feat/ohos_sha256_1.4.10-0.0.1 切换,并核对起点是否仍为本文参考版本。

3.4 自动补全 OHOS 适配结构

配套仓库已经包含 harmony/sha256/ 和 example/harmony/,直接运行示例时可以跳过结构生成。JS/TS 入口、原生 Package、C++ 桥接和宿主工程共同完成接线,不能只新建一个目录就称为适配完成。

库根目录提供 codegen:harmony 脚本,负责按目标 spec 生成 ArkTS/C++ 桥接;build:har 构建流程会调用它或对应的 build 脚本。消费者使用交付 HAR 时不再重复为该库运行 codegen。

3.5 适配后的项目目录

适配后的关键目录如下:

react-native-sha256/
├── package.json
├── sha256.js
├── src/NativeSha256.ts
├── harmony/
│   ├── sha256.har
│   └── sha256/
│       ├── index.ets
│       ├── oh-package.json5
│       └── src/main/
│           ├── ets/RNSha256TurboModule.ts
│           ├── ets/RNSha256Package.ets
│           ├── cpp/
│           └── module.json5
├── example/harmony/App.tsx
├── example/harmony/entry/
├── scripts/build-harmony.sh
├── README.harmony.md
└── VALIDATION.md
文件主要职责
sha256.js业务公开接口及 RN 层行为
src/NativeSha256.ts类型/模块协议
harmony/sha256/src/main/ets/RNSha256TurboModule.ts系统能力与生命周期
RNSha256Package.ets注册 UI TurboModule 工厂
RNSha256Package.hC++ Package 与模块映射
example/harmony/entry可安装宿主应用
example/harmony/App.tsx完整示例页面与诊断操作

四、JS/TS 接口与原生桥接分析

OHOS 实现需要遵循 JS/TS 层已有的方法、参数和回调约定。

对初学者来说,可以把这一层看成一条“传话链”:页面只负责调用公开函数,RNOH 负责把调用送到 ArkTS,ArkTS 负责访问系统 API,最后把成功结果或错误交回 JS/TS。只改页面代码而没有接好这条链,通常会得到“找不到原生模块”或“方法未实现”。先阅读 sha256.js 和 src/NativeSha256.ts,再查看 harmony/sha256/src/main/ets/RNSha256TurboModule.ts 的原生调用。适配其他已有平台的插件时,也应保留其公开接口和其他平台实现。

本例的对应关系如下:

公开入口模块协议OHOS 实现应保持的行为
sha1(text)sha256Lib.sha1cryptoFramework.createMd(“SHA1”)UTF-8;40 位小写十六进制
sha256(text)sha256Lib.sha256cryptoFramework.createMd(“SHA256”)UTF-8;64 位小写十六进制
sha1Bytes(bytes)sha256Lib.sha1BytesUint8Array → SHA1空数组有效
sha256Bytes(bytes)sha256Lib.sha256BytesUint8Array → SHA256建议 0–255 整数

4.1 跨端架构与调用时序

本例通过 RNOH UI TurboModule 执行系统调用,JS 模块名称为 sha256Lib。ArkTS 和 C++ Package 同时参与注册;JS/npm 依赖安装成功不代表原生模块已经接入。

React Native 页面

JS/TS 公开接口

RNOH sha256Lib

C++ 桥接

ArkTS UI TurboModule

HarmonyOS 系统能力

Promise 结果

4.1.1 一次完整调用的时序
系统能力 sha256Lib 公开 API RN 页面 系统能力 sha256Lib 公开 API RN 页面 系统结果或异常进入 Promise 调用公开方法 转发方法与参数 执行系统操作 Promise 完成或拒绝 按公开契约处理

4.2 数据模型与模块声明

以下声明来自 src/NativeSha256.ts:

// SPDX-License-Identifier: MIT
import type {TurboModule} from 'react-native';
import {TurboModuleRegistry} from 'react-native';

export interface Spec extends TurboModule {
  sha1(data: string): Promise<string>;
  sha1Bytes(data: number[]): Promise<string>;
  sha256(data: string): Promise<string>;
  sha256Bytes(data: number[]): Promise<string>;
}

export default TurboModuleRegistry.getEnforcing<Spec>('sha256Lib');

sha1/sha256 接受字符串并按 UTF-8 编码,分别返回 40/64 位小写十六进制 Promise。sha1Bytes/sha256Bytes 接受 number[]。每次调用独立创建摘要实例,支持并发;没有监听、权限或释放接口。

4.3 公开 API 与接口封装

以下为 sha256.js 的完整实现:

/** react-native-sha256 — native bridges for Android, iOS and OpenHarmony. */
'use strict';
const {NativeModules, Platform, TurboModuleRegistry} = require('react-native');
const sha256Lib = Platform.OS === 'harmony'
  ? TurboModuleRegistry.getEnforcing('sha256Lib')
  : NativeModules.sha256Lib;
exports.sha256 = data => sha256Lib.sha256(data);
exports.sha256Bytes = data => sha256Lib.sha256Bytes(data);
exports.sha1 = data => sha256Lib.sha1(data);
exports.sha1Bytes = data => sha256Lib.sha1Bytes(data);

4.4 模块协议与资源处理

原生端需要保持模块名、方法名及参数语义一致。sha256Lib 是桥接标识,不等同于 npm 包名或 HAR 文件名。

每次 hash 都创建独立 md,不共享可变摘要状态,无需公开释放方法。页面可以并发调用四种 API;卸载时只忽略结果,不声称已经取消系统摘要任务。整数模 256 行为沿用 Uint8Array,跨平台业务推荐只传合法 0–255 整数。


五、补全 OHOS 原生实现与工程配置

这一章只处理鸿蒙侧文件。插件 HAR 负责提供原生能力,example/harmony/entry 负责把这些能力装进一个可以安装的 HAP;两者都配置好,手机上的示例页面才有机会调用到系统功能。

5.1 在 RNSha256TurboModule.ts 中实现原生能力

业务沿用第四节公开接口;下面按源码说明原生层如何完成系统调用、结果转换和异常处理。

5.1.1 引入 RNOH 与系统能力

原生文件位于 harmony/sha256/src/main/ets/RNSha256TurboModule.ts。本例实现继承 UITurboModule,通过 this.ctx 获取宿主运行时上下文。

5.1.2 核心实现与错误处理

字符串先编码,字节数组转 Uint8Array;非空输入执行 md.update,空输入直接 md.digest。逐字节 toString(16).padStart(2,“0”) 保留前导零。API 24 空字符串编码可能返回 undefined,当前实现显式构造空 Uint8Array,仍由系统计算摘要,不硬编码空串结果。

以下为该原生文件的完整源码:

// SPDX-License-Identifier: MIT
import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import { util } from '@kit.ArkTS';
import { UITurboModule } from '@rnoh/react-native-openharmony/ts';
import { sha256Lib } from './generated/turboModules/sha256Lib';

export class RNSha256TurboModule extends UITurboModule implements sha256Lib.Spec {
  static readonly NAME: string = 'sha256Lib';

  async sha1(data: string): Promise<string> {
    return this.hash(this.encodeUtf8(data), 'SHA1');
  }

  async sha256(data: string): Promise<string> {
    return this.hash(this.encodeUtf8(data), 'SHA256');
  }

  async sha1Bytes(data: number[]): Promise<string> {
    return this.hash(new Uint8Array(data), 'SHA1');
  }

  async sha256Bytes(data: number[]): Promise<string> {
    return this.hash(new Uint8Array(data), 'SHA256');
  }

  private encodeUtf8(data: string): Uint8Array {
    // API 24 TextEncoder.encodeInto('') can return undefined at runtime.
    // Keep empty messages on the native digest path using an explicit buffer.
    return data.length === 0 ? new Uint8Array(0) : new util.TextEncoder().encodeInto(data);
  }

  private async hash(data: Uint8Array, algorithm: string): Promise<string> {
    // Never share digest state between overlapping calls.
    const md = cryptoFramework.createMd(algorithm);
    // An empty digest is valid; the native update API requires nonempty data.
    if (data.length > 0) {
      await md.update({ data });
    }
    const digest = await md.digest();
    let result = '';
    for (let i = 0; i < digest.data.length; i++) {
      result += digest.data[i].toString(16).padStart(2, '0');
    }
    return result;
  }
}
5.1.3 调用结束与实例销毁

每次 hash 都创建独立 md,不共享可变摘要状态,无需公开释放方法。页面可以并发调用四种 API;卸载时只忽略结果,不声称已经取消系统摘要任务。整数模 256 行为沿用 Uint8Array,跨平台业务推荐只传合法 0–255 整数。

5.2 声明插件和宿主权限

本库上述系统能力无需额外运行时权限,不应沿用其他传感器或定位库的权限清单。

5.2.1 插件 HAR 的权限

harmony/sha256/src/main/module.json5 声明 HAR 模块,本库没有额外 requestPermissions。能力是否存在仍需按系统和设备判断。

5.2.2 应用 entry 的权限

example/harmony/entry/src/main/module.json5 中的 ohos.permission.INTERNET 用于 RN 宿主的调试连接,不是此库读取或操作系统能力所必需的授权。

最终安装的是宿主应用。修改 module 配置时应合并现有字段,保留原有 Ability 等配置;权限声明和运行时授权是两个步骤。

5.3 注册并导出插件

ArkTS Package 注册如下,对应文件为 harmony/sha256/src/main/ets/RNSha256Package.ets:

// SPDX-License-Identifier: MIT
import { RNOHPackage, UITurboModule, UITurboModuleContext } from '@rnoh/react-native-openharmony';
import { RNSha256TurboModule } from './RNSha256TurboModule';

export class RNSha256Package extends RNOHPackage {
  getUITurboModuleFactoryByNameMap(): Map<string, (ctx: UITurboModuleContext) => UITurboModule> {
    return new Map<string, (ctx: UITurboModuleContext) => UITurboModule>([
      [RNSha256TurboModule.NAME, (ctx: UITurboModuleContext): UITurboModule => new RNSha256TurboModule(ctx)]
    ]);
  }
}

C++ Package 对应文件为 harmony/sha256/src/main/cpp/RNSha256Package.h:

// SPDX-License-Identifier: MIT
#pragma once
#include "RNOH/generated/BaseReactNativeOhosReactNativeSha256Package.h"
namespace rnoh {
class RNSha256Package : public BaseReactNativeOhosReactNativeSha256Package {
 public:
  explicit RNSha256Package(Package::Context ctx)
      : BaseReactNativeOhosReactNativeSha256Package(ctx) {}
};
} // namespace rnoh

HAR 入口 harmony/sha256/index.ets 导出 Package:

// SPDX-License-Identifier: MIT
export * from './ts';
export { RNSha256Package, RNSha256Package as default } from './src/main/ets/RNSha256Package';

package.json 中的自动链接元数据如下:

{
  "harmony": {
    "alias": "react-native-sha256",
    "autolinking": {
      "ohPackageName": "@react-native-ohos/react-native-sha256",
      "etsPackageClassName": "RNSha256Package",
      "cppPackageClassName": "RNSha256Package",
      "cmakeLibraryTargetName": "rnoh_sha256"
    }
  }
}

宿主启用自动链接后,还必须调用生成的 ArkTS/C++ 工厂,并在 CMake 中包含 autolinking.cmake、执行 autolink_libraries(rnoh_app)。只生成文件不等于接入完成。自动和手动注册选择一种,避免重复注册同一个 Package。

5.4 检查 example 的 OHOS 应用结构

示例工程的 example/harmony/build-profile.json5 同时包含 entry 和库模块。下面只列出需要关注的配置,合并时保留其他模块:

{
  "modules": [
    {
      "name": "entry",
      "srcPath": "./entry",
      "targets": [
        {
          "name": "default",
          "applyToProducts": [
            "default"
          ]
        }
      ]
    },
    {
      "name": "sha256",
      "srcPath": "../../harmony/sha256",
      "targets": [
        {
          "name": "default",
          "applyToProducts": [
            "default"
          ]
        }
      ]
    }
  ]
}

配置后,在 DevEco Studio 中执行一次 Sync Project。如果 entry 模块正常识别,Project 视图中会出现 entry,并能打开 entry 模块的签名配置。


六、补全交付文件并提交适配分支

6.1 除代码外还要补全哪些文件

代码适配完成后,还需要整理安装说明、接口文档、版本记录和开源信息。接收仓库有专用模板时,按其格式填写:

文件应写清楚的内容
README.OpenSource上游名称、源码地址、基线版本与 MIT 许可
README.md / README.upstream.md项目说明、上游信息与平台入口
README.harmony.md鸿蒙安装、配套版本、权限、接口和限制
VALIDATION.md测试、构建、设备场景及未覆盖项
LICENSE保留上游许可证和版权
package.json / index 类型入口包名、版本、导出、构建脚本与发布文件;类型入口按实际 package.json
harmony/sha256/oh-package.json5OHPM 依赖、原生入口与版本
harmony/sha256.har已构建的 release HAR,含消费者所需 C++ 源码
.gitignore排除构建缓存和本机签名材料

README.OpenSource 记录库本身的来源与版本。本例上游为 react-native-sha256 1.4.10,交付包为 @react-native-ohos/react-native-sha256 1.4.10-0.0.1;RN 和 HarmonyOS SDK 版本写入环境说明。OAT.xml 的语法有效性与官方扫描结果应分别记录。

6.2 提交前检查

提交前先完成第八节的插件、example 和真机测试,再从根目录检查改动:

git branch --show-current
git diff --check
git status --short
git diff --stat
git diff

检查 diff 中的接口、平台注册和依赖变化,移除本机路径及签名信息,并使文档中的版本和分支与提交内容一致。

6.3 提交并推送到 AtomGit

文档和代码整理完成后,在自己的维护分支根目录暂存并提交。以下文件清单覆盖本库主要改动,新增其他文件时逐项补充:

git add package.json sha256.js src/NativeSha256.ts harmony scripts
git add README.md README.harmony.md README.OpenSource VALIDATION.md
git diff --cached --check
git diff --cached --stat
git diff --cached
git commit -m "docs: document OHOS support for react-native-sha256 1.4.10-0.0.1"
git remote -v
git branch --show-current
git push -u origin feat/ohos_sha256_1.4.10-0.0.1

DevEco 可能向 example/harmony/build-profile.json5 写入本机签名配置,需要在提交前从暂存内容中移除。暂存 example 时逐文件核对;推送时,origin 应指向自己有权限的 AtomGit 仓库,当前分支为前面创建的维护分支。

推送后在 AtomGit 发起合并请求,说明上游来源和版本、OHOS 实现范围、依赖及权限、测试环境、操作结果、已知限制,并附 Demo 运行图。目标分支和评审流程以接收仓库要求为准。


七、使用插件包内 example 演示接入

这一章站在使用者角度操作:先安装依赖,再让示例应用找到插件,最后点击页面按钮或执行调用。遇到问题时,先确认示例使用的是本章指定的包来源,避免把上游包和鸿蒙适配包混在一起。

仓库自带 example/,可以直接用来调试插件和体验SHA 哈希计算。鸿蒙实际页面为 example/harmony/App.tsx,原生工程为 example/harmony。

7.1 本地适配时使用源码依赖

源码联调使用 example/harmony/metro.config.js 和 scripts/build-harmony.sh;不要改成 file:../,否则可能跳过仓库已有的 Harmony 配置。Metro 的项目根目录、watchFolders、别名和入口配置共同决定 JS 来源;示例 OHPM 指向库源码模块。只修改 JavaScript 后可以重新打包;原生代码变化还需重新构建。

按仓库文档,在插件根目录安装对应工具依赖:

npm ci --legacy-peer-deps
cd example/harmony
npm ci
cd ../..

安装完成后,终端会回到命令提示符,并在项目中生成或更新 node_modules 与锁文件;如果出现红色错误,先解决依赖安装问题,不要直接进入构建步骤。

下面是本库的 Harmony Metro 配置。上游 Android/iOS 配置不能直接用于鸿蒙:

const path = require('path');
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
const {createHarmonyMetroConfig} = require('@react-native-oh/react-native-harmony/metro.config');
const projectRoot = __dirname;
module.exports = mergeConfig(
  getDefaultConfig(projectRoot),
  createHarmonyMetroConfig({reactNativeHarmonyPackageName: '@react-native-oh/react-native-harmony'}),
  {
    projectRoot,
    watchFolders: [path.resolve(__dirname, '../..')],
    resolver: {
      disableHierarchicalLookup: true,
      nodeModulesPaths: [path.join(__dirname, 'node_modules')],
      extraNodeModules: {'react-native-sha256': path.resolve(__dirname, '../..')},
    },
    transformer: {babelTransformerPath: require.resolve('./transformer')},
  },
);

7.2 通过 AtomGit 源码构建并引入插件

当前没有可直接安装的 npm 版本。先按第三章从 AtomGit 获取固定提交,构建并打包,再在业务应用中安装生成的 tgz 文件。Git 仓库地址不能直接当作 npm 依赖使用。

以下命令在插件根目录执行;先完成 7.1 的依赖安装:

npm run build:har
mkdir -p artifacts
npm pack --pack-destination artifacts

产物名为 react-native-ohos-react-native-sha256-1.4.10-0.0.1.tgz。在采用 RN 0.84.1 / RNOH 0.84.3 的业务应用 JS 根目录执行,将绝对路径改为本机生成的文件位置:
把下一条命令中的 /absolute/path/to/...tgz 替换为你实际生成的 tgz 文件路径;示例路径不能直接照抄。

npm install /absolute/path/to/react-native-ohos-react-native-sha256-1.4.10-0.0.1.tgz
npx react-native link-harmony --harmony-project-path ./harmony
cd harmony
ohpm install

上述消费工程假设原生根目录为 harmony/。布局不同应调整 --harmony-project-path 和依赖路径。应用的 Harmony Metro 应使用 createHarmonyMetroConfig;包内 harmony.alias 支持上游导入名 react-native-sha256,TypeScript 的 paths 需要独立配置。下面最小页面直接使用适配包名,避免依赖 TypeScript 别名。

自动链接生成工厂后按 5.3 接入宿主。如果选择手动接入,ArkTS 注册 RNSha256Package、C++ 注册 rnoh::RNSha256Package,CMake 添加 HAR 内的 src/main/cpp 并链接 rnoh_sha256。完整手动工程见仓库 example/harmony/entry。

检查业务应用的依赖锁文件、实际 node_modules 和 OHPM 锁文件,确认 JS 与 HAR 来自同一版本,不要混用上游包的 JS 和另一个版本的原生实现。

7.3 调用接口实现SHA 哈希计算

下面是已安装适配包的 RNOH 业务应用可使用的最小 App.tsx,保留本库的公开 API。

若要在仓库源码示例中使用,按 example/harmony/App.tsx 的相对位置与现有源码解析配置调整 import,保留注册入口。不要覆盖 Android/iOS 的历史示例入口。

import React, {useEffect, useRef, useState} from 'react';
import {Button, ScrollView, Text, TextInput} from 'react-native';
import {sha1, sha256, sha1Bytes, sha256Bytes} from '@react-native-ohos/react-native-sha256';

export default function App() {
  const [input, setInput] = useState('abc');
  const [result, setResult] = useState('尚未计算');
  const alive = useRef(false);
  const requestId = useRef(0);
  useEffect(() => {
    alive.current = true;
    return () => { alive.current = false; requestId.current += 1; };
  }, []);
  async function calculate() {
    const id = ++requestId.current;
    const text = input;
    setResult('计算中');
    try {
      const [sha1Text, sha256Text, sha1ABC, sha256ABC] = await Promise.all([
        sha1(text), sha256(text), sha1Bytes([97, 98, 99]), sha256Bytes([97, 98, 99]),
      ]);
      if (alive.current && id === requestId.current)
        setResult(JSON.stringify({input: text, sha1Text, sha256Text,
          byteInput: [97, 98, 99], sha1ABC, sha256ABC}, null, 2));
    } catch (error) {
      if (alive.current && id === requestId.current) setResult(String(error));
    }
  }
  return (
    <ScrollView contentContainerStyle={{padding: 24, gap: 16}}>
      <TextInput value={input} onChangeText={setInput}
        style={{borderWidth: 1, padding: 12}} placeholder="输入文本,空串也有效" />
      <Button title="计算四个接口" onPress={() => void calculate()} />
      <Text>字符串方法使用输入框文本;字节方法固定使用 abc 的 UTF-8 字节。</Text>
      <Text selectable>{result}</Text>
    </ScrollView>
  );
}

7.4 页面退出时处理资源

每次 hash 都创建独立 md,不共享可变摘要状态,无需公开释放方法。页面可以并发调用四种 API;卸载时只忽略结果,不声称已经取消系统摘要任务。整数模 256 行为沿用 Uint8Array,跨平台业务推荐只传合法 0–255 整数。


八、验证、构建与鸿蒙设备运行效果

建议按“工具链—设备—构建产物—页面功能”的顺序排查。先确认命令能运行,再确认 hdc 能看到设备,然后检查是否生成 HAP,最后才判断插件功能;这样可以快速分辨是环境问题、安装问题还是接口问题。 文中的 <device-id> 是占位符,请用 hdc list targets 输出的真实设备 ID 替换。

8.1 分别验证插件与 example

以下命令作为复现步骤,在已完成 7.1 安装的插件仓库根目录执行:

npm test
npm run typecheck
npm run build:har
npm run build:example
npm run verify:integration

verify:integration 会创建一个临时应用,检查 npm 包、HAR、自动链接和打包能否一起工作。命令运行前先准备好应用的签名配置;如果使用过临时工程,后续直接按该工程的构建流程继续即可。

测试覆盖输入转换、异常处理、空字符串和固定摘要向量。摘要结果仍应在鸿蒙设备上用中文、Emoji、ASCII 等实际输入确认。

源码测试覆盖接口和业务逻辑;系统能力与设备行为需要在鸿蒙环境中验证。

8.2 确认设备连接

hdc list targets

设备首次连接电脑时,需要在手机端确认调试授权。列表为空时,检查 USB 连接、调试模式和电脑授权。

8.3 配置签名

真机安装的 HAP 通常需要有效签名。推荐使用 DevEco Studio 为 entry 模块配置签名:

  1. 用 DevEco Studio 打开 example/harmony,不是仓库根目录;
  2. 等待工程 Sync 成功,确认 Project 视图中存在 entry 模块;
  3. 打开 File > Project Structure > Signing Configs;
  4. 为 default product 选择或生成签名;
  5. 确认设备、应用包名、证书和 Profile 匹配;
  6. 再回到终端执行构建,或在 DevEco 运行 entry。

签名材料保存在本机,公开仓库中只保留构建所需的通用配置。HAR 不需要应用签名;要验收最终交付 HAR,应使用独立 npm 消费宿主,而不是以源码宿主代替。

8.4 运行示例

从插件根目录构建源码示例:

npm run build:example

本库脚本生成离线生产 JS bundle,并构建默认 debug HAP,不要求另开 Metro 服务。典型产物位于:

example/harmony/entry/build/default/outputs/default/

未签名文件 entry-default-unsigned.hap 仅能说明打包完成。配置有效签名并生成 entry-default-signed.hap 后,可在仓库根目录安装:

hdc -t <device-id> install -r example/harmony/entry/build/default/outputs/default/entry-default-signed.hap

将 <device-id> 替换为设备列表中的实际 ID;安装后从设备应用图标启动,或在 DevEco 直接运行 entry。构建工具默认来自 macOS DevEco Studio,其他位置使用脚本支持的 DEVECO_ROOT、DEVECO_SDK_HOME、OHPM_BIN、HVIGOR_JS 配置。

8.5 在设备上测试核心操作

  1. 启动示例应用,确认所有摘要用例都返回预期结果。
  2. 重新运行全部验证,确认同一进程仍全部通过。
  3. 冷启动、后台恢复后重复验证,检查并发结果。
  4. 输入自定义中英文及 Emoji,对照独立摘要工具;空串和空数组也需参与测试。

页面默认值或“已请求”文本不等于系统操作完成。查询要检查结果来源,监听要观察真实事件,窗口操作要观察实际系统显示。

8.6 鸿蒙设备运行效果

首次调用、重复调用、冷启动和后台恢复都能完成摘要计算;中文、Emoji 和 ASCII 文本的 SHA-1、SHA-256 结果与标准实现一致。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

| 2 | 中文、Emoji 与 ASCII 输入 |
| 3 | 后台恢复后的摘要计算 |

示例覆盖公开 API、原生直调、固定向量和并发调用。最低 API 17、其他平台回归和真机加密服务故障注入,需要在相应环境中另行测试。


九、FAQ:适配过程与使用问题

9.1 Missing SDK components

这个错误发生在 Hvigor 同步阶段。通常需要检查构建工具使用的 SDK 路径、组件是否完整,以及 Hvigor 与 SDK 的版本是否匹配。

处理顺序:

  1. 在 DevEco Studio SDK Manager 中确认 API 26 组件已经下载完整;
  2. 检查构建脚本与 DevEco 使用的 SDK 路径是否一致;
  3. 根据实际安装位置设置 DEVECO_SDK_HOME 或其他工具覆盖变量;
  4. 确认 SDK 包中工具链、ETS、JS 和 native 组件可用;
  5. 重新执行 DevEco Studio Sync,并查看脚本输出的构建日志。
为什么连接 API 24 手机仍然会报这个错误?

因为 Sync 和 Compile 首先读取 Mac 本地 SDK。手机 API 版本只在部署、安装和运行时参与兼容判断。即使完全不连接手机,本地 SDK 不完整时也会得到相同错误。

当前工程的 compatibleSdkVersion 是 API 17,因此 API 24 在安装版本门槛上是满足的;但设备还必须支持本库使用的能力,并满足签名要求。

9.2 DevEco Studio 中看不到 entry 模块

插件的 harmony/sha256 目录是 HAR 模块,可安装应用的 entry 模块位于 example/harmony/entry。

请直接使用 DevEco Studio 打开:

react-native-sha256/example/harmony

如果仍看不到 entry,先解决 SDK Sync 错误,再检查应用 build-profile 的 modules 是否包含 ./entry。同步失败时,Project Structure 无法正确解析模块,签名界面也可能不显示 entry。

9.3 无法手动签名

签名配置依附于可构建的应用模块和 product。只有 HAR 插件模块、工程 Sync 失败,或者打开了错误目录时,DevEco Studio 都可能无法提供 entry 签名入口。

建议先确认:

  • 打开的是 example/harmony;
  • SDK 组件完整并且 Sync 成功;
  • entry 的模块类型为 entry;
  • default product 和 target 已正确关联;
  • 当前账号、证书和调试设备状态有效。

9.4 空字符串为什么也要计算摘要

空消息是有效输入。当前实现显式创建空缓冲并调用原生 digest,避免 API 24 TextEncoder 空值;不返回硬编码摘要。

9.5 找不到原生模块 sha256Lib

这通常表示 JS 入口找不到已注册的原生模块。新增原生插件后需要重新构建应用;检查 npm 适配包、OHPM HAR、ArkTS Package、C++ Package 和 CMake 链接,特别是自动工厂是否真正由宿主调用。不要用一个固定返回值或开发刷新替代原生接入。

9.6 重复操作或页面退出后的行为

每次 hash 都创建独立 md,不共享可变摘要状态,无需公开释放方法。页面可以并发调用四种 API;卸载时只忽略结果,不声称已经取消系统摘要任务。整数模 256 行为沿用 Uint8Array,跨平台业务推荐只传合法 0–255 整数。

9.7 编译成功但安装失败

常见原因包括:

  • HAP 未签名或使用了错误的 Profile;
  • 设备未加入调试设备列表;
  • 包名与签名 Profile 不匹配;
  • 安装包的 compatibleSdkVersion 高于设备 API;
  • 手机上已经安装了使用不同证书签名的同包名应用。

根据安装错误码区分签名、版本和包名冲突,再处理对应配置。

9.8 RN CLI 或 Metro 使用了错误入口

在对应依赖目录确认安装的是本文配套 RN/RNOH 和 Harmony CLI。使用 example/harmony/metro.config.js,检查包的 react-native/main 入口与 Harmony 平台选择;Metro 别名不会自动给 TypeScript 提供 paths。调试时不要同时加载上游包和适配包的不同实现。

9.9 AtomGit 依赖提示找不到分支或无权限

先检查 URL 是否指向已同步的目标仓库,再确认需要的分支已推送。本文已固定到 27d87ed3e0221ca72284644a685aec17815ca501;自己新建的 feat/ohos_sha256_1.4.10-0.0.1 不会自动存在于远端。私有 Fork 还需在本机配置 Git 认证。

9.10 改了本地 ArkTS,Demo 为什么没变化

先检查应用消费的是源码模块还是打包的 HAR:已安装的 tgz 不会自动读取工作区修改。本地源码联调按 7.1 的配置,测试交付包则重建 HAR、重新打包并更新宿主依赖与 OHPM 锁文件。原生代码变动后停止应用并重新构建运行,不能只做 JS Fast Refresh。

9.11 为什么 iOS 与鸿蒙对内嵌 NUL 可能不同

上游 iOS strlen 会截断 NUL 后内容;鸿蒙与 Android 计算完整 UTF-8 内容。跨平台协议应明确输入字节,不能假定历史实现无差异。


相关链接

Logo

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

更多推荐