如果你在OpenHarmony上做资讯类App,十个有九个会直接扑向ArkUI,但我当时的情况比较特殊:手上已经有一套在iOS和Android上跑得很顺的React Native版Steam资讯App,重新用ArkUI把每个页面画一遍,成本高得让人肉疼。这篇文章记录的就是我在OpenHarmony上用RN(React Native)移植Steam资讯App,并且把"特惠游戏"模块真正落地跑通的全过程。内容不涉及复杂的系统源码,主要面向有RN基础、想把现有业务快速迁到OpenHarmony上的开发者。你可以把它当成一份实战笔记,里面的工程配置、数据解析、卡片实现和踩坑排查链路,都是我实际跑过、验证过的。
1. 为什么是"RN + OpenHarmony"这套组合来做Steam资讯
1.1 一个我反复被问的问题
"OpenHarmony不是有ArkUI吗,为什么还绕一圈用RN?"这是我每次发相关帖子都会被问到的问题。答案其实分两层:第一层是业务复用。资讯类App重逻辑、轻系统能力,页面无非就是列表、详情、收藏、设置,RN代码里绝大部分可以直接平移过来,不需要重新实现。第二层是团队成本。团队里已经有一批熟练的RN开发,让他们去学ArkUI再写一遍业务,培养周期和排期成本都是实际压力。
但选择RN这套组合也有很实在的代价。OpenHarmony上的RN生态远没有Android和iOS成熟,很多npm包装上去就跑不起来,轻则某个原生模块找不到,重则直接白屏。所以这个项目从一开始就不是"无脑复用",而是"能用纯JS解决的坚决不碰原生依赖"。
1.2 OpenHarmony上RN的现状与选型判断
先说结论:OpenHarmony上跑RN已经不是一个"能不能跑"的问题,而是"跑起来之后你要填多少坑"的问题。社区维护的react-native-openharmony适配方案,核心思路是把RN的JS运行时和渲染链路接到OpenHarmony的组件体系上,RN的生命周期、组件树、事件分发都保留下来,只是底层的Native View换成了OpenHarmony自己的实现。换句话说,RN业务代码基本不变,但原生依赖需要逐个确认兼容性。
选型时我最关注两方面:一是RN版本,二是原生依赖的轻重。RN版本上,我当时用的是社区适配比较成熟的0.72.x,因为那个版本对应的issue和示例最多,遇到问题能搜到答案。后来也有更新的版本被适配,但我个人不推荐项目中途升级RN大版本,尤其是这类跨平台移植项目,升一次版本的排查面太大了。
至于原生依赖,我的判断标准很简单:一个npm包如果底层依赖了Android的View系统或者iOS的UIKit,它在OpenHarmony上大概率不能直接跑。纯TS/JS实现的库(比如axios、dayjs、zustand)基本没问题,UI组件库和系统能力库就需要万分谨慎。不同情况的选择可以参考下面这个表:
| 项目情况 | 我的建议 | 说明 |
|---|---|---|
| 已有RN项目要迁移 | 保持原RN大版本 | 避免连带升级所有原生依赖 |
| 从零开始的新项目 | 选社区适配最活跃的版本 | 示例多、踩坑记录多 |
| 重度依赖原生SDK(相机/地图/蓝牙) | 暂时别迁移 | 等对应SDK的OH适配方案 |
| 依赖很少的资讯/电商类项目 | 可以动手 | 优先用纯JS库替代原生模块 |
1.3 特惠游戏功能在整个资讯App里的定位
为什么要先把"特惠游戏"这个模块单独拎出来做?因为这个模块几乎覆盖了资讯类App的所有典型技术点:远程HTTP请求、列表渲染与滚动性能、远端图片加载、金额计算与格式化、倒计时状态管理、收藏与本地缓存、跨页面跳转。做完特惠模块,其他的资讯列表、评测文章、促销日历基本就是换一套数据源的复制粘贴。
我的实操习惯是先挑最麻烦的模块验证技术路线。特惠模块对数据准确性和性能要求都不低,能在OpenHarmony上把这个功能跑顺,就说明这套RN方案对整个App是可行的。如果一开始只做个静态展示页,后面遇到真正的复杂交互时才发现路线走不通,返工成本就大了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 工程初始化:OpenHarmony侧的RN适配要动哪些东西
2.1 不要从示例仓库改起
很多人喜欢先把OpenHarmony官方示例工程拉下来,然后删掉Demo页面往里面填业务代码。这种做法的坑在于:示例工程会捆绑大量为了演示功能而引入的原生依赖,你删代码的时候很难判断某一个依赖到底被谁引用了,删不干净后面全是隐患。我推荐的做法完全反过来,先用RN官方cli初始化一个标准RN工程,再把react-native核心依赖替换成适配OpenHarmony的版本,然后单独引入harmony壳工程。这样工程结构还是标准的RN结构,业务代码和OpenHarmony原生壳完全分离。
我当时的初始化步骤大致如下:
bash复制# 1. 创建RN工程,带上具体版本
npx @react-native-community/cli init SteamSpecial --version 0.72.10
# 2. 进入工程,把react-native替换为OH适配版本
npm install @react-native-oh/react-native --save
完成之后,工程根目录下会有一套标准的RN源码结构,同时多出一个harmony目录。接下来用DevEco Studio打开harmony目录,等首次构建完成,再把应用部署到模拟器或者开发板上。这里我特别提醒一句:不要为了省事去复制别人项目的整个node_modules,依赖版本一旦不对,跑起来的问题会非常难查。
2.2 HarmonyOS工程侧的配置:权限、签名和bundle加载
RN for OpenHarmony的工程配置里,有三个地方最容易忽略,而且每一个都会直接导致运行失败。
第一是网络权限。HarmonyOS的应用默认是没有网络访问能力的,必须在module.json5里显式声明ohos.permission.INTERNET权限。这个权限不配置的话,表现非常诡异:Metro打包服务连不上、远程图片加载不出来、接口请求全部失败,而且报错信息还不一定直接指向权限问题。
json5复制{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
]
}
}
第二是签名。DevEco Studio调试时通常会自动生成一个调试签名,连接模拟器没问题,但如果是真机或者RK3568这类开发板,就需要去AppGallery Connect申请并配置自己的调试签名,否则安装阶段就会被系统拦下来。这个问题通常会以"Install Failed"的形式出现,但有些板子甚至只提示"未安装应用",很容易让人误判成代码问题。
第三是bundle加载地址。RN应用在Debug模式下要靠Metro打包服务提供JS Bundle,默认地址是localhost:8081。模拟器上跑没问题,但装到真机或开发板上时,设备里的localhost指向的是设备自己,不是你的电脑。这时候需要把开发机上8081端口的数据映射到设备上,让设备能访问到Metro服务:
bash复制hdc reverse tcp:8081 tcp:8081
这个命令我在调试期间几乎每次重连设备都要执行一次,后面第5章会专门展开讲。
2.3 推荐的最小目录结构和依赖清单
特惠模块跑通之后,我整理了一份最小可运行的项目结构,给准备
