2601_94997069头像
React Native 三方库「react-native-version-check」的鸿蒙化适配指南封面图

React Native 三方库「react-native-version-check」的鸿蒙化适配指南

开发工具: 华为云码道

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

上游仓库: kimxogus/react-native-version-check.git

react-native-version-check 将应用版本读取、商店地址生成和版本比较封装为 React Native 接口,可以用在“关于应用”和“检查更新”等页面。本文以 @react-native-ohos/react-native-version-check 3.5.0-0.0.1 为例,介绍源码准备、OHOS 工程配置、原生实现和示例运行。

本适配保留上游 Android/iOS 实现,新增鸿蒙支持。源码位于 AtomGit 配套仓库,文中的代码以提交 edd7c21deedb3f55b073009cc42375581c1cc954 为参考。配套仓库包含对应的鸿蒙实现和示例工程。


在这里插入图片描述

给初学者的阅读提示:
这个仓库包含多个包。本文操作的插件目录是 packages/react-native-version-check/,里面的 example/ 是鸿蒙示例应用。除第三章拉取仓库的步骤外,命令默认在插件目录执行。

HAR 是插件的鸿蒙原生模块包,HAP 是安装到手机上的应用包。RNOH 负责连接 React Native 与鸿蒙,ArkTS 用来调用鸿蒙系统能力,TurboModule 负责 JS 与原生模块之间的调用,Metro 负责打包 JS/TS 代码。

一、插件简介与适配目标

检查更新通常要回答三个问题:手机上安装的是哪个版本,线上最新版本是多少,以及新版本是否比当前版本更新。这个库分别提供读取应用信息、查询最新版本和比较版本的方法,下载与安装由业务应用另行处理。

例如,“关于应用”页面可以直接显示 getCurrentVersion() 返回的版本号;用户点击“检查更新”后,应用可以从自己的服务器读取版本,再交给 needUpdate() 比较。

鸿蒙原生模块负责四项数据:系统地区、应用包名、版本号和构建号。版本比较和商店查询仍在 JavaScript 层执行。这里读取的版本来自安装到设备上的应用配置,与 npm 插件版本是两回事。

鸿蒙默认使用上游的 Google Play 数据源。应用如果通过其他渠道发布,需要传入自定义 provider,也就是“获取最新版本的函数”;本适配没有提供 AppGallery 版本查询。


二、环境准备

环境搭建参考社区文档:React Native OpenHarmony 环境初始化,完成 Node.js、RN/RNOH 依赖、环境变量和 DevEco Studio 配置;框架能力与版本关系见 ohos_react_native。

在开发电脑的终端执行以下命令,macOS 和 Windows PowerShell 均可使用:

node --version
npm --version
hdc list targets

前两条命令应输出版本号;hdc list targets 应列出已连接的鸿蒙设备或模拟器。列表为空时,先检查 USB 调试授权或模拟器连接。

项目版本或配置用途
Node.js满足 React Native 0.84.1 的 engines 要求执行 npm、Metro 和构建脚本
React Native0.84.1示例应用的 RN 版本
React19.2.3与示例应用配套
RNOH / Harmony CLI0.84.3鸿蒙运行层和命令行工具
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 工程
适配包版本3.5.0-0.0.1npm 插件版本
原生实现ArkTS / C++系统信息读取与 RNOH 桥接
插件产物harmony/version_check.har供业务应用引入的原生模块包

根目录保留了上游旧工具链配置,运行鸿蒙示例时应使用插件目录的 package.json。其中 peerDependencies 的范围比本文的配套环境更宽,首次接入建议先使用表中的 RN/RNOH 组合。

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

example/harmony/build-profile.template.json5 中的 product 配置如下:

{
  "name": "default",
  "compileSdkVersion": "26.0.0",
  "compatibleSdkVersion": "5.0.5(17)",
  "targetSdkVersion": "26.0.0",
  "runtimeOS": "HarmonyOS"
}

compileSdkVersion 决定电脑上需要安装哪个 SDK,compatibleSdkVersion 决定应用声明的最低安装门槛。IDE 版本、编译 SDK 和手机系统版本分别影响不同环节,不能相互替代。最低兼容版本上的实际行为仍需在对应环境测试。


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

3.1 将上游源码同步到 AtomGit

本例上游为 kimxogus/react-native-version-check,基线版本为 3.5.0,采用 MIT 许可证。配套 AtomGit 仓库已经包含鸿蒙适配代码,运行示例时直接克隆即可。

需要独立维护时,可以在 AtomGit 创建自己的 Fork,保留上游许可证、源码和提交历史。仓库中的 packages/react-native-version-check-expo 是另一个包,本文介绍的是 packages/react-native-version-check。

3.2 将代码拉取到宿主机

在准备存放项目的目录执行以下命令,macOS 和 Windows PowerShell 共用:

git clone https://atomgit.com/oh-react-native/react-native-version-check.git
cd react-native-version-check
git switch --detach edd7c21deedb3f55b073009cc42375581c1cc954
git status --short --branch

git clone 会创建仓库目录;git switch --detach 将源码固定到本文使用的版本。已有本地修改时,先提交或保存修改,再切换版本。

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

配套仓库使用 master 分支。需要继续修改时,从前面的固定提交创建自己的维护分支:

git switch -c feat/ohos_version_check_3.5.0-0.0.1
cd packages/react-native-version-check

此后所在位置就是本文的插件目录。这里能看到 package.json、harmony/ 和 example/。仅查看源码时,也可以不创建分支,直接进入插件目录。

3.4 说明现有 OHOS 适配结构

仓库已经包含 harmony/version_check/ 原生库模块和 example/harmony/ 应用工程。首次使用先在插件目录安装依赖:

npm install

安装成功后应生成 node_modules/。这里按仓库文档使用 npm install;不要在仓库根目录运行同名命令来代替插件依赖安装。

直接用 DevEco Studio 打开示例前,还需将模板复制为本地工程配置。macOS 在插件目录执行:

if [ ! -f example/harmony/build-profile.json5 ]; then
  cp example/harmony/build-profile.template.json5 example/harmony/build-profile.json5
fi

Windows PowerShell 在同一目录执行:

if (-not (Test-Path 'example/harmony/build-profile.json5')) {
  Copy-Item 'example/harmony/build-profile.template.json5' 'example/harmony/build-profile.json5'
}

以上命令只在配置不存在时复制。之后选择 DevEco Studio 的 Open,打开 packages/react-native-version-check/example/harmony。已有配置中可能包含本机签名,应继续使用已有文件。

npm run codegen:harmony 根据 src/NativeVersionCheck.ts 生成 ArkTS/C++ 桥接文件。系统信息如何读取由第五章的原生代码实现;codegen 不会代写业务逻辑。

3.5 适配后的项目目录

react-native-version-check/
├── package.json
├── examples/reactnative/              上游 Android/iOS 示例
└── packages/
    ├── react-native-version-check-expo/
    └── react-native-version-check/    本文的插件目录
        ├── package.json
        ├── index.harmony.js
        ├── builder.js
        ├── index.d.ts
        ├── src/
        │   ├── NativeVersionCheck.ts
        │   ├── RNVersionInfo.harmony.js
        │   ├── getLatestVersion.js
        │   └── needUpdate.js
        ├── harmony/
        │   ├── version_check.har
        │   └── version_check/
        │       ├── index.ets
        │       └── src/main/
        │           ├── ets/RNVersionCheckTurboModule.ts
        │           ├── ets/RNVersionCheckPackage.ets
        │           ├── cpp/
        │           └── module.json5
        ├── example/
        │   ├── App.js
        │   ├── index.js
        │   ├── metro.config.js
        │   └── harmony/entry/
        ├── scripts/build-harmony.sh
        ├── scripts/bundle-example.cjs
        ├── README.harmony.md
        └── VALIDATION.md
文件主要职责
index.harmony.js / builder.js组合鸿蒙信息读取与公共版本检查方法
src/RNVersionInfo.harmony.js保持上游同步、异步接口形式
src/NativeVersionCheck.ts声明原生模块名和返回字段
RNVersionCheckTurboModule.ts读取系统地区与宿主应用版本
RNVersionCheckPackage.ets / RNVersionCheckPackage.h注册 ArkTS 与 C++ 模块
example/App.js展示应用信息、刷新和版本比较
example/harmony/entry/hvigorfile.ts在应用构建前生成 JS bundle

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

这个库的接口分为两部分:当前应用信息来自鸿蒙原生模块,最新版本查询和版本比较由 JS 实现。接入时既要注册原生模块,也要配置好用于查询版本的数据源。

公开入口模块协议或 JS 逻辑OHOS 实现或数据来源返回行为
getCountry()RNVersionCheck.getConstants()i18n.System.getSystemRegion()Promise<string>
getPackageName()同上BundleInfo.name同步 string
getCurrentVersion()同上BundleInfo.versionName同步 string
getCurrentBuildNumber()同上BundleInfo.versionCode同步 number
getLatestVersion(options)src/getLatestVersion.js默认 Google Play,也支持自定义 provider异步返回版本字符串
needUpdate(options)src/needUpdate.js使用 semver 比较版本异步返回比较结果
getStoreUrl() / getPlayStoreUrl()src/getStoreUrl.js鸿蒙默认拼接 Google Play 地址异步返回 URL
getAppStoreUrl(options)同上根据 appID 等参数拼接 Apple 商店地址异步返回 URL

getCountry() 返回的是系统地区,不代表定位结果。getPlayStoreUrl() 只生成地址,不会检查应用是否已经上架。要查询最新版本,需要应用在对应商店有可访问的信息,或由业务提供自己的版本接口。

4.1 跨端架构与调用时序

React Native 页面

VersionCheck 公开接口

当前应用信息

RNVersionCheck TurboModule

系统地区与应用包信息

最新版本查询

Google Play 或自定义 provider

JS semver 版本比较

4.1.1 一次完整调用的时序
鸿蒙系统 RNVersionCheck VersionCheck RN 页面 鸿蒙系统 RNVersionCheck VersionCheck RN 页面 getCurrentVersion() getConstants() 读取 BundleInfo 与系统地区 应用信息 四个字段组成的对象 currentVersion 字符串

getCurrentVersion() 是同步方法。getCountry() 保留上游 Promise 形式,但内部同样先读取原生字段。

4.2 数据模型与模块声明

src/NativeVersionCheck.ts 定义了原生模块协议:

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

export interface VersionCheckConstants {
  country: string;
  packageName: string;
  currentBuildNumber: number;
  currentVersion: string;
}

export interface Spec extends TurboModule {
  getConstants(): VersionCheckConstants;
}

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

假设宿主应用的 versionName 为 1.0.0、versionCode 为 1000000,相应方法就返回这两个值。插件自己的 3.5.0-0.0.1 用来标识依赖版本,不会成为业务应用的版本号。

needUpdate() 返回 isNeeded、currentVersion、latestVersion 和 storeUrl。例如比较 1.0.0 与 1.1.0 时,isNeeded 为 true。设置 depth: 1 时只比较第一段,两个版本都会按 1.0.0 比较,此时结果为 false。

4.3 公开 API 与接口封装

鸿蒙入口 index.harmony.js 将平台信息读取对象交给上游 builder,由它组合出完整 API:

// @flow
import VersionInfo from './src/RNVersionInfo.harmony';
import builder, { type ReactNativeVersionCheck } from './builder';

const RNVC: ReactNativeVersionCheck = builder(VersionInfo);

export default RNVC;

src/RNVersionInfo.harmony.js 保持各方法的返回形式:

// @flow
import NativeVersionCheck from './NativeVersionCheck';

export default {
  getCountry: (): Promise<string> =>
    Promise.resolve(NativeVersionCheck.getConstants().country),
  getPackageName: (): string =>
    NativeVersionCheck.getConstants().packageName,
  getCurrentBuildNumber: (): number =>
    NativeVersionCheck.getConstants().currentBuildNumber,
  getCurrentVersion: (): string =>
    NativeVersionCheck.getConstants().currentVersion,
};

getConstants() 每次调用都会读取系统信息,代码中没有保存首次读取结果的缓存。若系统调用抛出异常,三个同步方法会直接抛出;getCountry() 中的原生调用也可能在 Promise.resolve() 执行前抛出,因此可以将 await VersionCheck.getCountry() 放在 try/catch 中一起处理。

4.4 最新版本查询与错误处理

最容易上手的方式是先传入两个固定版本,理解比较规则:

const result = await VersionCheck.needUpdate({
  currentVersion: '1.0.0',
  latestVersion: '1.1.0',
  ignoreErrors: false,
});
console.log(result.isNeeded); // true

接入自己的服务器时,provider 函数需要返回版本字符串。下面的 versionApiUrl 是业务配置中的 HTTPS 接口地址,服务器响应格式约定为 { "version": "1.1.0" }:

import VersionCheck from '@react-native-ohos/react-native-version-check';

async function checkFromServer(versionApiUrl: string) {
  const latestVersion = await VersionCheck.getLatestVersion({
    provider: async () => {
      const response = await fetch(versionApiUrl);
      if (!response.ok) throw new Error(`版本接口请求失败:${response.status}`);
      const data: unknown = await response.json();
      if (typeof data !== 'object' || data === null ||
          !('version' in data) || typeof data.version !== 'string') {
        throw new Error('版本接口没有返回有效的 version 字符串');
      }
      return data.version;
    },
    ignoreErrors: false,
  });
  return VersionCheck.needUpdate({latestVersion, ignoreErrors: false});
}

这里省略 currentVersion 后,库会读取当前应用版本。调用 checkFromServer() 的页面应捕获异常并显示“检查失败”,避免把请求失败显示成“已经是最新版本”。

传入 latestVersion 后,needUpdate() 不再查询 provider,所以结果中的 storeUrl 是空字符串。自定义更新渠道的跳转地址应由业务配置或服务器提供,点击更新时再使用对应地址。

默认 ignoreErrors: true 会在部分异常路径记录警告并返回 undefined,类型声明没有完整反映这些路径。需要向用户展示失败原因时,建议显式设置 ignoreErrors: false。forceUpdate 也不是“强制用户安装更新”的开关,是否强制升级由业务页面决定。


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

插件 HAR 提供信息读取能力,example/harmony/entry 将它注册到可安装的应用中。原生模块读到的是这个宿主应用的信息。

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

5.1.1 引入 RNOH 与系统能力

原生文件位于 harmony/version_check/src/main/ets/RNVersionCheckTurboModule.ts。它继承 UITurboModule,使用 bundleManager 读取本应用信息,使用 i18n 读取系统地区。

5.1.2 核心实现与错误处理

以下是该原生文件的完整实现:

// SPDX-License-Identifier: MIT

import bundleManager from '@ohos.bundle.bundleManager';
import { i18n } from '@kit.LocalizationKit';
import { UITurboModule } from '@rnoh/react-native-openharmony/ts';
import { RNVersionCheck } from './generated/turboModules/RNVersionCheck';

export interface VersionCheckConstants {
  country: string;
  packageName: string;
  currentBuildNumber: number;
  currentVersion: string;
}

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

  getConstants(): VersionCheckConstants {
    const bundleInfo = bundleManager.getBundleInfoForSelfSync(
      bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT,
    );
    return {
      country: i18n.System.getSystemRegion(),
      packageName: bundleInfo.name,
      currentBuildNumber: bundleInfo.versionCode,
      currentVersion: bundleInfo.versionName,
    };
  }
}

getBundleInfoForSelfSync() 中的 Self 表示读取当前应用。代码没有查询其他应用,也没有把示例包名写死在插件里。系统异常会沿调用链返回给 JS,业务页面可以据此显示失败原因。

5.1.3 调用结束与实例销毁

本库没有持续订阅系统事件,也不提供 removeListener()。页面如果需要在系统地区改变后更新显示,可以再次调用读取方法;退出页面时只需管理应用自己发起的异步操作。

5.2 声明插件和宿主权限

5.2.1 插件 HAR 的权限

harmony/version_check/src/main/module.json5 声明模块类型为 har,没有额外的 requestPermissions。读取本应用版本和系统地区无需用户授予定位或电话权限。

5.2.2 应用 entry 的权限

example/harmony/entry/src/main/module.json5 声明了网络权限:

{
  "requestPermissions": [
    { "name": "ohos.permission.INTERNET" }
  ]
}

该配置放在 module 对象内部。联网查询商店或自定义版本接口需要网络权限,Metro 调试连接也会使用网络。它无需弹出运行时授权窗口;只读取本地版本号或比较两个给定版本时,不需要联网。

5.3 注册并导出插件

ArkTS 的 RNVersionCheckPackage.ets 注册模块工厂:

// SPDX-License-Identifier: MIT

import { RNOHPackage, UITurboModule, UITurboModuleContext } from '@rnoh/react-native-openharmony';
import { RNVersionCheckTurboModule } from './RNVersionCheckTurboModule';

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

C++ 的 RNVersionCheckPackage.h 继承 codegen 生成的 Package:

// SPDX-License-Identifier: MIT
#pragma once

#include "RNOH/generated/BaseReactNativeOhosReactNativeVersionCheckPackage.h"

namespace rnoh {
class RNVersionCheckPackage
    : public BaseReactNativeOhosReactNativeVersionCheckPackage {
 public:
  explicit RNVersionCheckPackage(Package::Context ctx)
      : BaseReactNativeOhosReactNativeVersionCheckPackage(ctx) {}
};
} // namespace rnoh

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

// SPDX-License-Identifier: MIT

export * from './ts';
export { RNVersionCheckPackage } from './src/main/ets/RNVersionCheckPackage';
export { RNVersionCheckPackage as default } from './src/main/ets/RNVersionCheckPackage';

package.json 提供的自动链接配置如下:

{
  "harmony": {
    "alias": "react-native-version-check",
    "autolinking": {
      "ohPackageName": "@react-native-ohos/react-native-version-check",
      "etsPackageClassName": "RNVersionCheckPackage",
      "cppPackageClassName": "RNVersionCheckPackage",
      "cmakeLibraryTargetName": "rnoh_version_check"
    }
  }
}

使用自动链接的业务应用,需要在 ArkTS 和 C++ 宿主工厂中调用生成的 createRNOHPackages,并在 CMake 中包含 autolinking.cmake、调用 autolink_libraries(rnoh_app)。

仓库源码示例采用手动注册:ArkTS 的 RNPackagesFactory.ets 返回 new RNVersionCheckPackage(ctx),C++ 的 PackageProvider.cpp 返回 std::make_shared<RNVersionCheckPackage>(ctx),CMake 添加插件的 src/main/cpp 并链接 rnoh_version_check。接入自己的应用时选择其中一种注册方式,避免同一模块注册两次。

5.4 检查 example 的 OHOS 应用结构

example/harmony/build-profile.template.json5 同时声明应用和插件模块:

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

示例的 entry/oh-package.json5 引入源码模块:

{
  "name": "entry",
  "version": "1.0.0",
  "description": "Version check example",
  "dependencies": {
    "@rnoh/react-native-openharmony": "0.84.3",
    "@react-native-ohos/react-native-version-check": "file:../../../harmony/version_check"
  }
}

配置后在 DevEco Studio 执行 Sync Project,Project 视图中应出现 entry。example/index.js 注册的组件名称为 VersionCheckExample,与原生 pages/Index.ets 中的 appKey 保持一致。

entry/hvigorfile.ts 在 default@PreBuild 前调用 scripts/bundle-example.cjs,将 JS 代码打包到 entry/src/main/resources/rawfile/bundle.harmony.js。因此从 DevEco 启动构建也会生成 JS bundle,应用可以使用内置资源启动。


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

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

文件应写清楚的内容
README.md / README.upstream.md项目用途和上游使用说明
README.harmony.md鸿蒙接入步骤、配套版本与能力范围
README.OpenSource / LICENSE上游 3.5.0 版本及 MIT 许可证
package.json / index.d.ts包名、入口、依赖和公开类型
harmony/version_check/oh-package.json5HAR 入口与 RNOH 依赖
harmony/version_check.har业务应用需要的原生模块包
OAT.xml / COMMITTERS.md / CODE_OF_CONDUCT.md开源文件配置与社区维护说明
VALIDATION.md测试方法和适用范围
.gitignore排除构建缓存与本机配置

HAR 的构建配置包含 C++ 桥接源码,release 模式开启 ArkTS 混淆。修改原生实现后,需重新生成 harmony/version_check.har 再打包 npm 依赖。

6.2 提交前检查

先完成第八章的检查与设备操作,再在插件目录查看差异:

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

核对接口、模块注册和依赖变化,确认文档与代码使用同一版本。example/harmony/build-profile.json5 是本地配置,模板文件负责保存可共享的工程结构。

6.3 提交并推送到 AtomGit

需要提交自己的维护改动时,在插件目录执行以下命令。macOS 和 Windows PowerShell 共用:

git add package.json index.harmony.js builder.js index.d.ts src harmony scripts tests
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 "feat: support version checking on HarmonyOS"
git remote -v
git push -u origin feat/ohos_version_check_3.5.0-0.0.1

origin 应指向自己有写权限的仓库。推送后可在 AtomGit 发起合并请求,说明原生信息来源、默认商店行为、示例接入方式和测试范围。


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

鸿蒙示例位于 packages/react-native-version-check/example,页面文件为 App.js。仓库根目录的 examples/reactnative 是上游 Android/iOS 示例,运行鸿蒙应用时使用包内的 example/harmony。

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

按第三章安装插件依赖后,example/metro.config.js 将两个导入名都指向插件源码:

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 = path.resolve(__dirname, '..');
module.exports = mergeConfig(
  getDefaultConfig(projectRoot),
  createHarmonyMetroConfig({reactNativeHarmonyPackageName: '@react-native-oh/react-native-harmony'}),
  {
    projectRoot,
    transformer: {babelTransformerPath: require.resolve('./transformer')},
    resolver: {
      extraNodeModules: {
        '@react-native-ohos/react-native-version-check': projectRoot,
        'react-native-version-check': projectRoot,
      },
    },
  },
);

example/package.json 中的 file:.. 同样指向插件目录;鸿蒙原生工程通过第五章的 OHPM 路径引用源码模块。这里的 JS 依赖与 HAR 依赖是两层配置。

常规运行使用第八章的构建流程。需要单独启动 Metro 时,在插件目录执行:

npm --prefix example start

终端启动 Metro 服务后,可以用于 JS 调试;安装和启动鸿蒙应用仍通过 DevEco Studio 完成。仓库根目录没有 start 脚本。

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

需要让自己的业务应用使用本文版本时,可以先从源码构建 HAR,再生成本地 npm 压缩包。macOS 在插件目录执行:

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

输出文件为 artifacts/react-native-ohos-react-native-version-check-3.5.0-0.0.1.tgz。Windows 构建 HAR 的方法见 8.1;将产物复制到 harmony/version_check.har 后,在插件目录打包:

New-Item -ItemType Directory -Force artifacts | Out-Null
npm pack --pack-destination artifacts

把生成的 tgz 文件复制到业务应用 JS 根目录,再执行以下命令。这里假设业务应用已经是 RN 0.84.1 / RNOH 0.84.3 工程,原生目录为 harmony/:

npm install ./react-native-ohos-react-native-version-check-3.5.0-0.0.1.tgz
npx react-native link-harmony --harmony-project-path ./harmony
cd harmony
ohpm install

自动链接后按 5.3 接好宿主工厂与 CMake。业务工程需配置 Harmony Metro,确保选中 index.harmony.js;harmony.alias 保留了 react-native-version-check 导入名。下面的 TypeScript 页面直接使用适配包名。

7.3 调用接口实现应用版本检查

在已接入原生模块的业务应用中,可以使用下面的最小 App.tsx。它先显示应用信息,再用两个明确给定的版本演示比较,运行这个页面不需要请求商店:

import React, {useCallback, useEffect, useRef, useState} from 'react';
import {Button, ScrollView, Text} from 'react-native';
import VersionCheck from '@react-native-ohos/react-native-version-check';

export default function App() {
  const [info, setInfo] = useState('尚未读取');
  const [result, setResult] = useState('尚未比较');
  const [busy, setBusy] = useState(false);
  const alive = useRef(false);
  const checking = useRef(false);
  const readId = useRef(0);

  const refresh = useCallback(async () => {
    const id = ++readId.current;
    try {
      const packageName = VersionCheck.getPackageName();
      const currentVersion = VersionCheck.getCurrentVersion();
      const buildNumber = VersionCheck.getCurrentBuildNumber();
      const country = await VersionCheck.getCountry();
      if (alive.current && id === readId.current) {
        setInfo(JSON.stringify({country, packageName, currentVersion, buildNumber}, null, 2));
      }
    } catch (error) {
      if (alive.current && id === readId.current) setInfo(String(error));
    }
  }, []);

  async function compare() {
    if (checking.current) return;
    checking.current = true;
    setBusy(true);
    try {
      const value = await VersionCheck.needUpdate({
        currentVersion: '1.0.0',
        latestVersion: '1.1.0',
        ignoreErrors: false,
      });
      if (alive.current) {
        setResult(`${value.currentVersion} → ${value.latestVersion}:${value.isNeeded ? '需要更新' : '无需更新'}`);
      }
    } catch (error) {
      if (alive.current) setResult(String(error));
    } finally {
      checking.current = false;
      if (alive.current) setBusy(false);
    }
  }

  useEffect(() => {
    alive.current = true;
    void refresh();
    return () => {
      alive.current = false;
      readId.current += 1;
    };
  }, [refresh]);

  return (
    <ScrollView contentContainerStyle={{padding: 24, gap: 16}}>
      <Text style={{fontSize: 24}}>应用版本</Text>
      <Button title="读取应用信息" onPress={() => void refresh()} />
      <Text selectable>{info}</Text>
      <Text>下面使用 1.0.0 和 1.1.0 演示版本比较。</Text>
      <Button title="比较示例版本" disabled={busy} onPress={() => void compare()} />
      <Text selectable>{result}</Text>
    </ScrollView>
  );
}

要改为查询线上版本,可以将 compare() 中的固定版本比较替换为 4.4 的 checkFromServer() 调用,并传入业务版本接口地址。保留错误处理,服务器不可用时显示检查失败。

7.4 页面退出时处理资源

示例使用 alive 判断页面是否仍然存在,避免异步结果在页面退出后更新 UI;readId 让较早的读取结果不会覆盖新结果。库本身没有事件订阅,因此不需要注销原生监听。

如果自定义 provider 使用 fetch,取消网络请求由业务自己的 AbortController 管理。页面不再接收结果,并不会自动取消已经发出的请求。


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

建议按“依赖安装 → 工程同步 → 应用构建 → 设备页面”的顺序排查。先让示例能启动,再检查版本值和业务更新接口。

8.1 分别验证插件与 example

macOS 在插件目录执行:

npm run typecheck
npm run test:harmony
npm run build:har
npm run verify:package
npm run build:example

typecheck 检查 TurboModule 类型,test:harmony 检查模块名称、字段和入口源码。它们不请求商店,也不模拟完整设备运行。build:har 先进行类型检查和 codegen,再生成原生模块包;build:example 构建包含 JS bundle 的示例应用。

需要检查打包后的依赖接入时,可以继续执行:

npm run verify:integration

verify:package 和 verify:integration 都会重建 artifacts/package-smoke 目录,前者检查包内容、类型与自动链接,后者还构建独立应用。应先运行这些命令,再为该临时应用配置签名;已经配置好的临时应用需要保留时,直接使用其工程构建流程。

构建脚本使用 Bash,并默认寻找 macOS 的 DevEco 安装目录。Windows PowerShell 可以先在插件目录执行:

npm run typecheck
npm run test:harmony
npm run codegen:harmony

然后用 DevEco Studio 打开 example/harmony 并完成 Sync,通过 Hvigor 任务选择 version_check 模块的 release assembleHar。输出位于 harmony/version_check/build/default/outputs/default/version_check.har,从插件目录复制:

Copy-Item 'harmony/version_check/build/default/outputs/default/version_check.har' 'harmony/version_check.har' -Force

运行示例时在 DevEco 选择 entry 构建并启动。Windows 操作依据工程任务配置整理,尚未在 Windows 环境实测;build:har、build:example 中的 Bash 命令不直接作为 PowerShell 命令运行。

8.2 确认设备连接

hdc list targets

设备首次连接电脑时,需要在手机端确认调试授权。列表为空时,检查 USB 连接、调试模式和电脑授权。后面的安装命令需要使用该列表中的设备 ID。

8.3 配置签名

  1. 用 DevEco Studio 打开 packages/react-native-version-check/example/harmony;
  2. 等待工程 Sync 成功,确认存在 entry 模块;
  3. 打开 File > Project Structure > Signing Configs;
  4. 为 default product 配置签名;
  5. 确认设备、应用包名、证书和 Profile 匹配;
  6. 重新构建并运行 entry。

HAR 无需应用签名,设备上安装的 HAP 使用宿主应用签名。签名设置保存在本地 build-profile.json5 中。

8.4 运行示例

macOS 可以在插件目录执行:

npm run build:example

脚本默认使用 /Applications/DevEco-Studio.app/Contents。安装位置不同,可以通过 DEVECO_ROOT 指定;SDK 或工具单独安装时,脚本还支持 DEVECO_SDK_HOME、OHPM_BIN 和 HVIGOR_JS。

应用产物位于:

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

配置签名并重新构建后,可以直接在 DevEco 运行,也可以从插件目录安装。macOS 示例中将 你的设备ID 替换为 hdc list targets 输出的值:

rnvc_device_id='你的设备ID'
hdc -t "$rnvc_device_id" install -r example/harmony/entry/build/default/outputs/default/entry-default-signed.hap

Windows PowerShell 使用:

$rnvcDeviceId = '你的设备ID'
hdc -t $rnvcDeviceId install -r 'example/harmony/entry/build/default/outputs/default/entry-default-signed.hap'

示例优先读取应用内的 bundle.harmony.js,不必先启动 Metro。安装成功后从设备桌面打开应用,页面应显示应用信息和两个操作按钮。

8.5 在设备上测试核心操作

  1. 打开仓库示例,检查地区、包名、当前版本和构建号是否有值。
  2. 对照 example/harmony/AppScope/app.json5 的 bundleName、versionName 和 versionCode,确认页面读取的是宿主应用配置。
  3. 点击 Refresh,重新读取信息;点击 Check update,查看固定目标版本的比较结果。
  4. 修改自己的应用版本配置后,重新构建安装,再确认页面显示新版本。只修改 JS 无法改变已安装应用的原生版本号。
  5. 接入自己的版本服务后,分别检查有更新、无更新、断网和响应格式错误时的页面行为。

8.6 鸿蒙设备运行效果

仓库示例可以显示系统地区、应用包名、版本号和构建号。使用示例配置时,包名为 com.example.rnversioncheck,版本号为 1.0.0,构建号为 1000000;系统地区选择中国时,地区字段为 CN。

在这里插入图片描述

点击 Refresh 可以重新读取这些字段。Check update 按钮使用 999.0.0 作为固定目标版本,因此相对于示例的 1.0.0 会显示需要更新。业务中应替换为实际版本服务返回的值。

示例中的 Play Store URL 根据包名拼接,Google Play 在线查询、业务更新地址跳转和其他平台的行为需要分别测试。最低兼容版本上的运行也需要单独确认。


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

9.1 Missing SDK components

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

在 DevEco Studio SDK Manager 中安装工程所需的 API 26 组件,再检查命令行与 IDE 使用的 SDK 路径是否一致,重新执行 Sync。

为什么连接手机后仍然提示缺少 SDK?

Sync 和 Compile 读取的是电脑上的 SDK。手机系统只参与安装与运行阶段的兼容判断,因此需要先补齐电脑上的工具链、ETS、JS 和 native 组件。

9.2 DevEco Studio 中看不到 entry 模块

先确认打开的是:

react-native-version-check/packages/react-native-version-check/example/harmony

再检查是否已按 3.4 生成 build-profile.json5,以及 Sync 是否成功。harmony/version_check 是插件模块,安装到设备上的应用模块在 example/harmony/entry。

9.3 无法手动签名

签名配置依附于可构建的应用模块和 product。确认 Project 视图中已有 entry、default product 正常,并检查账号、证书、应用包名和调试设备是否匹配。

9.4 为什么根目录运行 npm start 提示没有脚本

根目录没有 start 脚本。先进入 packages/react-native-version-check,运行示例使用 npm run build:example 或 DevEco;单独启动 Metro 使用 npm --prefix example start。

9.5 找不到原生模块 RNVersionCheck

检查 npm 包、OHPM 依赖、ArkTS Package、C++ Package 和 CMake 是否全部接入。getEnforcing('RNVersionCheck') 在加载模块时就会检查注册情况,因此应先解决原生接入,再测试业务方法。

原生模块变动后需要重新构建应用,JS 刷新无法补上尚未编译的原生代码。

9.6 应用启动时提示 JSBundleProvider 无法加载 bundle

先在插件目录完成 npm install,然后检查 example/harmony/entry/hvigorfile.ts 中的 bundleHarmonyExample 任务是否仍然存在。它会在构建前执行 scripts/bundle-example.cjs,生成 entry/src/main/resources/rawfile/bundle.harmony.js。

修复后重新构建并安装应用。只打开 Metro 不会把缺失的离线 bundle 写入已经安装的 HAP。

9.7 编译成功但安装失败

常见原因包括 HAP 未签名、设备未加入调试列表、包名与 Profile 不匹配、系统版本低于最低兼容要求,或设备中已有不同证书签名的同包名应用。先查看安装错误码,再处理对应配置。

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

确认终端位于插件目录,并使用 example/metro.config.js。鸿蒙平台应解析到 index.harmony.js 和 src/RNVersionInfo.harmony.js。示例还使用 example/transformer.js 固定 Babel 配置,避免受到仓库根目录旧配置影响。

9.9 AtomGit 分支、版本或依赖路径不对

配套仓库使用 master,本文源码固定到 edd7c21deedb3f55b073009cc42375581c1cc954。仓库包含多个包,直接把仓库根目录作为 npm 依赖会选错位置;按 7.2 从插件目录打包,再安装生成的 tgz。

9.10 修改了 ArkTS,页面为什么没有变化

源码示例与 tgz 安装使用的是不同来源。源码联调后重新构建 entry;使用 tgz 的业务应用则需重建 HAR、重新打包并更新依赖,再重新构建应用。

9.11 为什么没有查到 AppGallery 最新版本

本版本鸿蒙默认使用 Google Play provider。应用通过 AppGallery 或自有渠道发布时,使用 4.4 的自定义 provider 接入业务版本服务,下载或商店跳转地址也由业务管理。

9.12 为什么 storeUrl 为空,或检查后没有返回结果

显式传入 latestVersion 时,比较过程不查询商店,storeUrl 可以为空。检查版本失败时,默认忽略错误的路径还可能返回 undefined。使用 ignoreErrors: false 配合 try/catch,并单独配置业务更新地址。

9.13 npm install 提示缓存目录 EACCES

在插件目录换用可写的项目缓存:

npm install --cache ./artifacts/npm-cache

该命令适用于 macOS 与 Windows PowerShell。安装成功后再执行类型检查和构建。


相关链接

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2601_94997069/article/details/169550170

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--