这篇文章用一个使用 react-native CLI 创建的纯 RN 工程iOS 和 Android 都在跑里面用 expo-battery 读电池信息的 demo app 为例子给它加上了 HarmonyOS 支持业务代码一行没改同一份 App.tsx 现在跑在三个平台上。这篇文章把整个过程整理出来有同样需求的开发者可以照着走。expo-harmony 是什么AtomGit 仓库atomgit.com/baoshuo/expo-harmonyGitHub 仓库github.com/renbaoshuo/expo-harmony欢迎给上面这两个仓库点点 Star ~expo-harmony 是一个开源项目目标是让使用 Expo 模块的 React Native 应用跑在 HarmonyOS 上。它主要做三件事。一是给一批常用 Expo 模块补上鸿蒙的原生实现统一发布在 npm 的expo-harmony/scope 下目前有近百个包expo-battery、expo-location、expo-sqlite、expo-camera、expo-notifications 这些高频模块都在里面。二是提供expo-harmony命令行工具环境诊断、构建 HAP、选设备、安装、启动、管理 Metro一条命令串起来。三是支持自动链接装好包执行一次 link 命令原生模块的注册和构建配置都会生成不用逐个手写。工程形态上它支持两种。走 Expo CNG 的应用可以用 prebuild 直接生成鸿蒙原生工程。原生工程自己手工维护的应用走 bare 路线把一份现成的 harmony 工程模板拿进来改几个名字就能用。本文的应用属于后一种。它目前适配 Expo SDK 55 加 RNOH 0.84.1。RNOH 是 React Native for OpenHarmony鸿蒙侧的 RN 运行时版本号跟 React Native 对齐。仓库的 docs 目录 里有快速开始和 bare 接入两篇教程这篇文章的很多操作就是照着 bare 那篇做的。移植前的项目应用长什么样应用叫 ExpoSampleApp用react-native-community/cli创建react-native 和 react 固定在 0.84.1 和 19.2.3。npx react-native-community/cli init ExpoSampleApp\--version0.84.1\--package-name com.exposampleapp\--pmnpm选 0.84.1 不是随手挑的。RNOH 当前版本就是 0.84.1react-native 跟它对齐之后三个平台共用同一份 react 和 react-native 依赖不用在 Metro 里维护两套 RN 共存的别名方案省掉一堆配置。页面是一个电池面板。启动时用getPowerStateAsync读一次快照显示电量、电源状态和低电量模式同时挂三个监听器分别订阅电量、充电状态、低电量模式的变化。收到事件只做计数方便确认事件链路通不通。核心逻辑大概是这样。import * as Battery from expo-battery; // 读一次快照 const power await Battery.getPowerStateAsync(); // { batteryLevel: 0.45, batteryState: 2, lowPowerMode: false } // 订阅电量变化组件卸载时 subscription.remove() const subscription Battery.addBatteryLevelListener(({ batteryLevel }) { setEventCount(count count 1); });电量取值是 0 到 1 的浮点数取不到时返回 -1显示百分比之前要先处理这个未知值。还有一个写代码时的小细节SDK 55 的PowerState类型只有batteryLevel、batteryState、lowPowerMode三个字段没有batteryVoltage想多显示一行电压的话 tsc 会直接报错。这不是鸿蒙的问题各平台都一样。接入 Expo Modules先跑通 iOS 和 Android接入用的是官方install-expo-modules命令。这里有个坑命令内置一张 React Native 版本到 Expo SDK 的映射表它不认识 0.84.1直接跑会报Unable to find compatible Expo SDK version。加--sdk-version 55.0.0 --non-interactive显式指定就能过改出来的东西和官方 bare 流程一致Podfile 里多了use_expo_modules!Gradle 侧接上 expo-autolinkingAppDelegate 和 MainApplication 换成 Expo 提供的基类。npminstall--legacy-peer-deps\expo55.0.26 expo-modules-core55.0.26 expo-battery55.0.13\expo/metro-config55.0.27 expo/metro-runtime55.0.12 expo/log-box55.0.13 npx-yinstall-expo-modules --sdk-version55.0.0 --non-interactive另一个会卡住人的问题是版本差。Expo SDK 55 的原生代码是按 RN 0.83 写的配 0.84.1 编译不过。Android 侧是 RN 0.84.1 把Promise接口的code参数改成了可空expo-modules-core 的 Kotlin 实现还是旧签名。iOS 侧是RCTRootViewFactory的方法签名变了。两处改动都不大用 patch-package 打成补丁挂在 postinstall 里之后装依赖会自动应用。另外用 Xcode 26 的话AppDelegate 里的导入要写成internal import Expo不然 Swift 6.2 会报 ambiguous import。到这里 Android 和 iOS 都能跑了。Android 模拟器读出电量 100%AVD 默认就是满电电源状态未接电源点按钮重新读取也正常。iOS 模拟器上电量显示未知。这是正常表现iOS 模拟器没有电池仿真getPowerStateAsync返回 -1。模块本身工作正常调用没抛错监听和按钮都好使。所以在模拟器上验证模块接入看的是调用能不能走通、事件有没有流动别纠结具体数值。开始接入鸿蒙前置环境需要 DevEco Studio 和完整的 HarmonyOS SDKOHPM、Hvigor、hdc 这些工具要装齐Node 用 20 以上。模拟器在 DevEco Studio 的 Device Manager 里创建一个就行。环境有没有准备好后面 doctor 命令会挨个检查。安装鸿蒙侧依赖# Expo 鸿蒙适配包npminstall--legacy-peer-deps\expo-harmony/cli55.0.26-harmony.13 expo-harmony/metro-config55.0.26-harmony.4\expo-harmony/expo55.0.26-harmony.3 expo-harmony/expo-modules-core55.0.25-harmony.5\expo-harmony/expo-modules-autolinking55.0.25-harmony.5\expo-harmony/expo-battery55.0.13-harmony.5\react-native-ohos/react-native-safe-area-context5.6.4# RNOH 运行时与配套npminstall--save-exact --legacy-peer-deps\react-native-oh/react-native-harmony0.84.1 react-native-oh/react-native-harmony-cli0.84.1\react-native-worklets0.7.4 react-native-ohos/react-native-worklets1.0.0\hermes-compiler250829098.0.9几个包的分工说一下。expo-battery还是原来那个 JS 包业务代码继续从它 import。expo-harmony/expo-battery是对应的鸿蒙原生实现里面是编译好的 HAR 产物两个成对安装代码里的 import 不用动。expo-harmony/expo提供鸿蒙侧的应用宿主expo-harmony/expo-modules-core是 Expo Modules 的鸿蒙运行时。react-native-worklets要显式装 0.7.4。react-native-ohos/react-native-worklets自己依赖的版本是 0.7.1而expo-harmony/expo-modules-core的 peer 要求 0.7.4 以上所以要在根上把版本钉住。hermes-compiler用--save-exact它的版本要和 RNOH 原生包里内嵌的 Hermes 配套不能随手升。--legacy-peer-deps照旧加上。鸿蒙适配包声明了 RNOH 侧的 peer 依赖分步安装的中间态会让 npm 报冲突。如果项目里用了 react-native-safe-area-context 这类库鸿蒙侧再装对应的适配包这里是react-native-ohos/react-native-safe-area-context。官方包留着iOS 和 Android 继续用。适配包的 package.json 里有一段harmony.alias声明打包时 Metro 靠它把 import 自动重定向过去业务代码不用写任何平台分支。配置 Metro 和打包入口// metro.config.jsconst{getDefaultConfig}require(expo/metro-config);const{mergeConfig}require(react-native/metro-config);const{withHarmonyConfig}require(expo-harmony/metro-config);constconfig{};constisHarmonyprocess.env.EXPO_HARMONY1;module.exportswithHarmonyConfig(mergeConfig(getDefaultConfig(__dirname),config),{enabled:isHarmony,// expo-harmony 命令会自动设置 EXPO_HARMONY1projectRoot:__dirname,});withHarmonyConfig是 JS 侧的核心。enabled 用环境变量做开关expo-harmony命令跑起来会自动设置EXPO_HARMONY1平时 iOS 和 Android 的打包走原来的配置互不影响。鸿蒙打包生效时react-native 会被解析到 RNOH带harmony.alias声明的第三方库会被指到鸿蒙适配版Expo Modules 需要的初始化也会接进来。所以不要只给 react-native 手动配一个别名就完事那样初始化流程是缺的。再新建一个react-native.config.js一行就够。module.exportsrequire(react-native-oh/react-native-harmony-cli/react-native.config.js);Babel 不用动前面接 Expo 时已经换成 babel-preset-expo 了。package.json里补一个main字段指向 index.js再加四个脚本。{main:index.js,scripts:{start:harmony:expo-harmony start,run:harmony:expo-harmony run,build:harmony:expo-harmony build,doctor:harmony:expo-harmony doctor}}有一个名字对齐的要求容易漏。index.js 里AppRegistry.registerComponent注册的名字要和鸿蒙首页ExpoRNApp的 appKey 一致这里都是 ExpoSampleApp。对不上应用起不来报 appKey 未注册之类的错。准备 harmony 原生工程bare 路线不跑 prebuild原生工程从 apps/bare/harmony 整个复制过来。模板里要改的只有四个名字。文件改什么harmony/AppScope/app.json5bundleName 改成自己的harmony/AppScope/resources/base/element/string.json应用显示名harmony/entry/src/main/resources/base/element/string.jsonAbility 标签等harmony/entry/src/main/ets/pages/Index.etsappKey 对齐注册名bundleName 有个硬性要求至少三段。com.exposampleapp这种两段的会被 Hvigor 的校验直接拒绝后面补一段变成com.exposampleapp.app就过了。这个工程承担鸿蒙侧的全部原生工作ArkTS 的 Ability 和首页、C 侧的包注册、Hvigor 构建链都在里面。这些源文件提交进自己的仓库oh_modules 和构建产物加进 ignore。构建时自动生成的模块注册文件不用手写也不用提交。自动链接和原生依赖npx expo-harmony-autolinkinglink--project-root.--harmony-project-path ./harmonycdharmony ohpminstall--allcd..link 命令会解析当前装了哪些 Expo 模块生成 ArkTS 和 C 两侧的包注册文件并把鸿蒙原生依赖写进harmony/oh-package.json5。ohpm 的角色类似 CocoaPods装的是鸿蒙原生依赖。第一次构建前必须先跑这两步不然 Hvigor 找不到原生包。装完可以用npx expo-harmony-autolinking search看一眼识别结果这里识别出 4 个原生模块expo-harmony/expo、expo-harmony/expo-battery、expo-harmony/expo-modules-core和 worklets。safe-area-context 那种属于 JS 层的别名重定向不在原生模块清单里是正常的。环境检查与运行npmrun doctor:harmonydoctor 会过一遍环境和配置SDK 路径、hdc、ohpm、hvigorw、Metro 配置、识别到的原生模块一共 11 项。哪项红了照着提示修就行。npmrun run:harmonyrun 一条命令做完剩下所有事构建 debug HAP、选择或拉起模拟器、安装、启动应用、启动 Metro、设置端口反向映射。第一次构建要编译 C大概四五分钟之后就快了。机器上只有一个模拟器实例时会自动选它有多个就用--device指定。这里有个坑要提醒。如果之前给 iOS 或 Android 调试时起的 Metro 还挂在 8081 端口上run 会直接复用它但那个 Metro 没有鸿蒙的环境变量应用会报ERR_HARMONY_METRO_MANIFEST。切到鸿蒙之前先把旧的 Metro 停掉让 CLI 自己拉起一个带鸿蒙配置的。跑起来之后 Metro 日志里能看到 import 重定向的记录。[INFO] Redirected imports to 3 harmony-specific third-party package(s): [INFO] • expo-modules-core → expo-harmony/expo-modules-core [INFO] • react-native-safe-area-context → react-native-ohos/react-native-safe-area-context [INFO] • react-native-worklets → react-native-ohos/react-native-workletsreact-native 本身也指向了 RNOH。这些映射都来自各适配包里的harmony.alias声明由withHarmonyConfig执行没有一处需要手写。在鸿蒙模拟器上验证App 读出电量 45%和系统状态栏的电量图标一致。电源状态显示未知低电量模式关闭与模拟器的实际状态对得上。事件链路也验证了一下。DevEco 自带的 Emulator 命令行工具可以改模拟器电量执行一条-battery 80几秒后 App 的已收事件从 0 变成 1说明系统电量变化从原生监听一路送到了 JS 的addBatteryLevelListener。页面上的大数字还停在 45%这是因为 demo 的监听器只计数、不回写快照三个平台行为一致不是鸿蒙的问题。顺带把三个平台的电量读数差异放在这里。Android 的 AVD 默认满电读出来一般就是 100%。iOS 模拟器没有电池仿真读到未知。鸿蒙模拟器默认 45%还可以模拟任意电量。所以验证模块接入是否成功看调用能不能走通、事件有没有流动就够了数值本身随模拟器走。Release 构建用npm run build:harmony导出的 Hermes 字节码会内嵌进 HAP运行时不依赖 Metro。签名在harmony/build-profile.json5里配模拟器允许不签真机要装对应的证书和 profile。盘点一下改动接入鸿蒙这一步业务代码一行没改App.tsx 还是 iOS 和 Android 在用的那份。ios/ 和 android/ 两个目录没动。真正的改动是装了一组expo-harmony和 RNOH 的依赖metro.config.js 加了几行新建了一个一行的 react-native.config.jspackage.json 补了 main 和四个脚本再加一份从模板复制来的 harmony 工程模板里改的只有四个名字。对比一下不做这些要面对什么。自己写 expo-battery 的鸿蒙原生实现自己搭 Hvigor 工程自己处理每个模块的原生注册。expo-harmony 把这些活都包掉了应用多了一个平台业务代码还是原来那份。
企业数字化 ERP 产品动态
相关推荐
手把手教你用IDA Pro反汇编Xtensa指令集 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 1:29:13
Excel去重计数:COUNTIFS与UNIQUE/FILTER双路径实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 1:29:13
Keil MDK 5.37头文件找不到报错:AC6编译器Include Paths配置实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 1:29:13
Python机器学习算法实战:从数据到预测的完整实现与避坑指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 2:12:57
新注册公司怎么做网站速查手册 新注册公司怎么做网站避开低价陷阱的5条最佳实践 刚注册完公司,手里攥着几千块预算,想在三个月内把官网立起来?别急着在百度上搜“网站建设多少钱”,你大概率会看到一堆“99元建站”、“299元高端商城”的广告。我干了十年这行,见过太多老板为了省… · 2026/9/27 2:12:39
重学网工之-链路聚合手工模式 任务一:给LSW1和LSW2配置负载分担配置思路:
1.给所有终端配置ip地址
2.将PC1、PC3和PC2、PC4分别加入到vlan10和vlan20 且设置端口类型为access口
3.在lsw1和lsw2上分别进行链路聚合的配置,将G1、G2、G3端口加入到链路聚合中,
在链… · 2026/9/27 2:12:33
3步搞定网站主页图片尺寸,保姆级建站教程避坑指南 3步搞定网站主页图片尺寸,保姆级建站教程避坑指南 找建站公司最怕什么?不是技术不行,而是报价单里藏着无数隐形坑。你只想要个官网,对方却按“高端定制”收费,最后发现核心问题—— 主页图片尺寸… · 2026/9/27 2:12:33
第 2 天:Shell 是怎么启动另一个程序的? 昨天我们运行了 ./hello。程序从磁盘上的文件变成了进程,但中间留了一个问题:正在运行的 Shell,怎样让另一个程序跑起来?
在 Linux 中,常见做法可以概括为三个动作:
fork:创建子进程
exec&#… · 2026/9/27 2:12:27
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01