开发工具: 华为云码道
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 均可使用:
bash
node --version
npm --version
hdc list targets
前两条命令应输出版本号;hdc list targets 应列出已连接的鸿蒙设备或模拟器。列表为空时,先检查 USB 调试授权或模拟器连接。
| 项目 | 版本或配置 | 用途 |
|---|---|---|
| Node.js | 满足 React Native 0.84.1 的 engines 要求 | 执行 npm、Metro 和构建脚本 |
| React Native | 0.84.1 | 示例应用的 RN 版本 |
| React | 19.2.3 | 与示例应用配套 |
| RNOH / Harmony CLI | 0.84.3 | 鸿蒙运行层和命令行工具 |
| OHPM RNOH | 0.84.3 | 鸿蒙原生运行时依赖 |
| compileSdkVersion | 26.0.0 | 编译使用的 SDK |
| targetSdkVersion | 26.0.0 | 应用面向的系统行为版本 |
| compatibleSdkVersion | 5.0.5(17) | 工程声明的最低兼容版本 |
| DevEco Studio | 26.0.0 Release(HarmonyOS SDK 26.0.0 / API 26) | 打开并构建 example/harmony 工程 |
| 适配包版本 | 3.5.0-0.0.1 | npm 插件版本 |
| 原生实现 | ArkTS / C++ | 系统信息读取与 RNOH 桥接 |
| 插件产物 | harmony/version_check.har | 供业务应用引入的原生模块包 |
根目录保留了上游旧工具链配置,运行鸿蒙示例时应使用插件目录的 package.json。其中 peerDependencies 的范围比本文的配套环境更宽,首次接入建议先使用表中的 RN/RNOH 组合。
2.1 开发套件版本与工程中的 SDK 版本配置
example/harmony/build-profile.template.json5 中的 product 配置如下:
json5
{
"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 共用:
bash
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 分支。需要继续修改时,从前面的固定提交创建自己的维护分支:
bash
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/ 应用工程。首次使用先在插件目录安装依赖:
bash
npm install
安装成功后应生成 node_modules/。这里按仓库文档使用 npm install;不要在仓库根目录运行同名命令来代替插件依赖安装。
直接用 DevEco Studio 打开示例前,还需将模板复制为本地工程配置。macOS 在插件目录执行:
bash
if [ ! -f example/harmony/build-profile.json5 ]; then
cp example/harmony/build-profile.template.json5 example/harmony/build-profile.json5
fi
Windows PowerShell 在同一目录执行:
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 适配后的项目目录
text
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 跨端架构与调用时序
#mermaid-svg-60YfxHI6H5cW3uDS{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-60YfxHI6H5cW3uDS .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-60YfxHI6H5cW3uDS .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-60YfxHI6H5cW3uDS .error-icon{fill:#552222;}#mermaid-svg-60YfxHI6H5cW3uDS .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-60YfxHI6H5cW3uDS .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-60YfxHI6H5cW3uDS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-60YfxHI6H5cW3uDS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-60YfxHI6H5cW3uDS .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-60YfxHI6H5cW3uDS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-60YfxHI6H5cW3uDS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-60YfxHI6H5cW3uDS .marker{fill:#333333;stroke:#333333;}#mermaid-svg-60YfxHI6H5cW3uDS .marker.cross{stroke:#333333;}#mermaid-svg-60YfxHI6H5cW3uDS svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-60YfxHI6H5cW3uDS p{margin:0;}#mermaid-svg-60YfxHI6H5cW3uDS .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-60YfxHI6H5cW3uDS .cluster-label text{fill:#333;}#mermaid-svg-60YfxHI6H5cW3uDS .cluster-label span{color:#333;}#mermaid-svg-60YfxHI6H5cW3uDS .cluster-label span p{background-color:transparent;}#mermaid-svg-60YfxHI6H5cW3uDS .label text,#mermaid-svg-60YfxHI6H5cW3uDS span{fill:#333;color:#333;}#mermaid-svg-60YfxHI6H5cW3uDS .node rect,#mermaid-svg-60YfxHI6H5cW3uDS .node circle,#mermaid-svg-60YfxHI6H5cW3uDS .node ellipse,#mermaid-svg-60YfxHI6H5cW3uDS .node polygon,#mermaid-svg-60YfxHI6H5cW3uDS .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-60YfxHI6H5cW3uDS .rough-node .label text,#mermaid-svg-60YfxHI6H5cW3uDS .node .label text,#mermaid-svg-60YfxHI6H5cW3uDS .image-shape .label,#mermaid-svg-60YfxHI6H5cW3uDS .icon-shape .label{text-anchor:middle;}#mermaid-svg-60YfxHI6H5cW3uDS .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-60YfxHI6H5cW3uDS .rough-node .label,#mermaid-svg-60YfxHI6H5cW3uDS .node .label,#mermaid-svg-60YfxHI6H5cW3uDS .image-shape .label,#mermaid-svg-60YfxHI6H5cW3uDS .icon-shape .label{text-align:center;}#mermaid-svg-60YfxHI6H5cW3uDS .node.clickable{cursor:pointer;}#mermaid-svg-60YfxHI6H5cW3uDS .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-60YfxHI6H5cW3uDS .arrowheadPath{fill:#333333;}#mermaid-svg-60YfxHI6H5cW3uDS .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-60YfxHI6H5cW3uDS .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-60YfxHI6H5cW3uDS .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-60YfxHI6H5cW3uDS .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-60YfxHI6H5cW3uDS .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-60YfxHI6H5cW3uDS .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-60YfxHI6H5cW3uDS .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-60YfxHI6H5cW3uDS .cluster text{fill:#333;}#mermaid-svg-60YfxHI6H5cW3uDS .cluster span{color:#333;}#mermaid-svg-60YfxHI6H5cW3uDS div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-60YfxHI6H5cW3uDS .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-60YfxHI6H5cW3uDS rect.text{fill:none;stroke-width:0;}#mermaid-svg-60YfxHI6H5cW3uDS .icon-shape,#mermaid-svg-60YfxHI6H5cW3uDS .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-60YfxHI6H5cW3uDS .icon-shape p,#mermaid-svg-60YfxHI6H5cW3uDS .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-60YfxHI6H5cW3uDS .icon-shape .label rect,#mermaid-svg-60YfxHI6H5cW3uDS .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-60YfxHI6H5cW3uDS .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-60YfxHI6H5cW3uDS .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-60YfxHI6H5cW3uDS :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} React Native 页面
VersionCheck 公开接口
当前应用信息
RNVersionCheck TurboModule
系统地区与应用包信息
最新版本查询
Google Play 或自定义 provider
JS semver 版本比较
4.1.1 一次完整调用的时序
鸿蒙系统 RNVersionCheck VersionCheck RN 页面 鸿蒙系统 RNVersionCheck VersionCheck RN 页面 #mermaid-svg-Z5E6TV7DN9z1LX9f{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Z5E6TV7DN9z1LX9f .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Z5E6TV7DN9z1LX9f .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Z5E6TV7DN9z1LX9f .error-icon{fill:#552222;}#mermaid-svg-Z5E6TV7DN9z1LX9f .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Z5E6TV7DN9z1LX9f .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Z5E6TV7DN9z1LX9f .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Z5E6TV7DN9z1LX9f .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Z5E6TV7DN9z1LX9f .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Z5E6TV7DN9z1LX9f .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Z5E6TV7DN9z1LX9f .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Z5E6TV7DN9z1LX9f .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Z5E6TV7DN9z1LX9f .marker.cross{stroke:#333333;}#mermaid-svg-Z5E6TV7DN9z1LX9f svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Z5E6TV7DN9z1LX9f p{margin:0;}#mermaid-svg-Z5E6TV7DN9z1LX9f .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Z5E6TV7DN9z1LX9f text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-Z5E6TV7DN9z1LX9f .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Z5E6TV7DN9z1LX9f .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-Z5E6TV7DN9z1LX9f .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-Z5E6TV7DN9z1LX9f .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-Z5E6TV7DN9z1LX9f #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-Z5E6TV7DN9z1LX9f .sequenceNumber{fill:white;}#mermaid-svg-Z5E6TV7DN9z1LX9f #sequencenumber{fill:#333;}#mermaid-svg-Z5E6TV7DN9z1LX9f #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-Z5E6TV7DN9z1LX9f .messageText{fill:#333;stroke:none;}#mermaid-svg-Z5E6TV7DN9z1LX9f .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Z5E6TV7DN9z1LX9f .labelText,#mermaid-svg-Z5E6TV7DN9z1LX9f .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-Z5E6TV7DN9z1LX9f .loopText,#mermaid-svg-Z5E6TV7DN9z1LX9f .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-Z5E6TV7DN9z1LX9f .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Z5E6TV7DN9z1LX9f .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-Z5E6TV7DN9z1LX9f .noteText,#mermaid-svg-Z5E6TV7DN9z1LX9f .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-Z5E6TV7DN9z1LX9f .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Z5E6TV7DN9z1LX9f .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Z5E6TV7DN9z1LX9f .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Z5E6TV7DN9z1LX9f .actorPopupMenu{position:absolute;}#mermaid-svg-Z5E6TV7DN9z1LX9f .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-Z5E6TV7DN9z1LX9f .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Z5E6TV7DN9z1LX9f .actor-man circle,#mermaid-svg-Z5E6TV7DN9z1LX9f line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-Z5E6TV7DN9z1LX9f :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} getCurrentVersion() getConstants() 读取 BundleInfo 与系统地区 应用信息 四个字段组成的对象 currentVersion 字符串
getCurrentVersion() 是同步方法。getCountry() 保留上游 Promise 形式,但内部同样先读取原生字段。
4.2 数据模型与模块声明
src/NativeVersionCheck.ts 定义了原生模块协议:
typescript
// 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:
javascript
// @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 保持各方法的返回形式:
javascript
// @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 最新版本查询与错误处理
最容易上手的方式是先传入两个固定版本,理解比较规则:
typescript
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" }:
typescript
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 核心实现与错误处理
以下是该原生文件的完整实现:
typescript
// 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 声明了网络权限:
json5
{
"requestPermissions": [
{ "name": "ohos.permission.INTERNET" }
]
}
该配置放在 module 对象内部。联网查询商店或自定义版本接口需要网络权限,Metro 调试连接也会使用网络。它无需弹出运行时授权窗口;只读取本地版本号或比较两个给定版本时,不需要联网。
5.3 注册并导出插件
ArkTS 的 RNVersionCheckPackage.ets 注册模块工厂:
typescript
// 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:
cpp
// 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:
typescript
// 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 提供的自动链接配置如下:
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 同时声明应用和插件模块:
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 引入源码模块:
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.json5 | HAR 入口与 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 提交前检查
先完成第八章的检查与设备操作,再在插件目录查看差异:
bash
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 共用:
bash
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
示例工程有修改时再逐项加入对应文件,确认暂存内容没有本机签名和构建缓存。随后提交:
bash
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 将两个导入名都指向插件源码:
javascript
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 时,在插件目录执行:
bash
npm --prefix example start
终端启动 Metro 服务后,可以用于 JS 调试;安装和启动鸿蒙应用仍通过 DevEco Studio 完成。仓库根目录没有 start 脚本。
7.2 通过 AtomGit 源码构建并引入插件
需要让自己的业务应用使用本文版本时,可以先从源码构建 HAR,再生成本地 npm 压缩包。macOS 在插件目录执行:
bash
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 后,在插件目录打包:
powershell
New-Item -ItemType Directory -Force artifacts | Out-Null
npm pack --pack-destination artifacts
把生成的 tgz 文件复制到业务应用 JS 根目录 ,再执行以下命令。这里假设业务应用已经是 RN 0.84.1 / RNOH 0.84.3 工程,原生目录为 harmony/:
bash
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。它先显示应用信息,再用两个明确给定的版本演示比较,运行这个页面不需要请求商店:
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 在插件目录执行:
bash
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 的示例应用。
需要检查打包后的依赖接入时,可以继续执行:
bash
npm run verify:integration
verify:package 和 verify:integration 都会重建 artifacts/package-smoke 目录,前者检查包内容、类型与自动链接,后者还构建独立应用。应先运行这些命令,再为该临时应用配置签名;已经配置好的临时应用需要保留时,直接使用其工程构建流程。
构建脚本使用 Bash,并默认寻找 macOS 的 DevEco 安装目录。Windows PowerShell 可以先在插件目录执行:
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,从插件目录复制:
powershell
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 确认设备连接
bash
hdc list targets
设备首次连接电脑时,需要在手机端确认调试授权。列表为空时,检查 USB 连接、调试模式和电脑授权。后面的安装命令需要使用该列表中的设备 ID。
8.3 配置签名
- 用 DevEco Studio 打开
packages/react-native-version-check/example/harmony; - 等待工程 Sync 成功,确认存在
entry模块; - 打开 File > Project Structure > Signing Configs;
- 为
defaultproduct 配置签名; - 确认设备、应用包名、证书和 Profile 匹配;
- 重新构建并运行
entry。
HAR 无需应用签名,设备上安装的 HAP 使用宿主应用签名。签名设置保存在本地 build-profile.json5 中。
8.4 运行示例
macOS 可以在插件目录执行:
bash
npm run build:example
脚本默认使用 /Applications/DevEco-Studio.app/Contents。安装位置不同,可以通过 DEVECO_ROOT 指定;SDK 或工具单独安装时,脚本还支持 DEVECO_SDK_HOME、OHPM_BIN 和 HVIGOR_JS。
应用产物位于:
text
example/harmony/entry/build/default/outputs/default/
配置签名并重新构建后,可以直接在 DevEco 运行,也可以从插件目录安装。macOS 示例中将 你的设备ID 替换为 hdc list targets 输出的值:
bash
rnvc_device_id='你的设备ID'
hdc -t "$rnvc_device_id" install -r example/harmony/entry/build/default/outputs/default/entry-default-signed.hap
Windows PowerShell 使用:
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 在设备上测试核心操作
- 打开仓库示例,检查地区、包名、当前版本和构建号是否有值。
- 对照
example/harmony/AppScope/app.json5的bundleName、versionName和versionCode,确认页面读取的是宿主应用配置。 - 点击 Refresh ,重新读取信息;点击 Check update,查看固定目标版本的比较结果。
- 修改自己的应用版本配置后,重新构建安装,再确认页面显示新版本。只修改 JS 无法改变已安装应用的原生版本号。
- 接入自己的版本服务后,分别检查有更新、无更新、断网和响应格式错误时的页面行为。
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 模块
先确认打开的是:
text
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
在插件目录换用可写的项目缓存:
bash
npm install --cache ./artifacts/npm-cache
该命令适用于 macOS 与 Windows PowerShell。安装成功后再执行类型检查和构建。