大概是去年底,产品经理把一个需求拍到了我桌上:把现有 App 里的用户信息卡片搬到一块开源鸿蒙设备上,屏幕上跑的还必须是 OpenHarmony 系统。当时我第一反应是“这不得用 ArkUI 重写一遍”,但打开工程一看,逻辑层、接口层、状态管理全在 React Native 的 JS 代码里,真要重写,等于把整个业务再养一遍。
所以最终被推到台前的方案只有一个:React Native for OpenHarmony。这个方向在社区里常被简称为 rn_for_openharmony,也叫 RNOH。它做的不是把 RN 代码翻译成 ArkTS,而是保留 React Native 的 JS 框架和虚拟节点树,在 OpenHarmony 侧提供一个能和 ArkUI 对接的原生适配层。听起来很理想,但实际能不能把一张从草图演化来的用户信息卡片完整跑通,谁也没底。
这篇文章就是我那段时间的真实记录:从产品的手绘线稿开始,拆盒子、画布局、写组件,再到 RK3568 开发板上烧镜像、接真机、调 bug。如果你也在考虑把 RN 业务往 OpenHarmony 设备上迁移,这张卡片可以作为最小验证单元,帮你快速判断这条路的可行性和真正的成本在哪里。
1. 为什么我会把“一张用户信息卡片”当成试刀的第一关
1.1 这个组件到底验证了哪些技术点
选用户信息卡片作为第一个试点,不是因为 UI 简单,恰恰是因为它面积小但覆盖面够宽。一张普通到不能再普通的卡片,通常包含圆形头像、昵称、组织单位、联系方式、操作按钮这五类元素。放到 RN for OpenHarmony 的适配场景里,它背后的技术点大概是这些:
- 文本渲染:中文、数字、邮箱长文本的断行与截断表现。
- 图片能力:网络头像加载、圆角裁切、加载失败时的降级占位。
- 布局还原度:flexDirection、alignItems、flexShrink 这些属性在 OpenHarmony 适配层上是否真的生效。
- 层级表达:圆角、边框、阴影在 ArkUI 容器内的显示语义。
- 点击交互:触摸反馈、点击区域是否和 RN 在 Android/iOS 上一致。
- 列表复用:卡片进入 FlatList 之后,滚动性能和刷新是否正常。
这六点如果能全部通过,那后续页面里的列表页、详情页、表单组件基本上可以照方抓药。如果过不了,那你在代码量庞大之前就该知道问题在哪,而不是等整个业务迁移过去才发现跑不动。
1.2 RNOH 不等于“把代码拿过来就能跑”
先建立一个基本认知:React Native for OpenHarmony 并不是 React Native 官方直接支持的平台,它是开源社区和厂商共同推进的一个适配分支。它保留了 RN 的开发范式,但把原生侧的 iOS/Android 实现替换成了 OpenHarmony 能力。也就是说,你在 JSX 里写的 <View>、<Text>、<Pressable> 会被映射成 OpenHarmony 里的 ArkUI 组件或者自定义封装组件,再由原生渲染管线输出到屏幕。
但要注意,这种映射不是逐字逐句的翻译。RN 里很多样式属性依赖 iOS 的 Core Animation 或 Android 的 Material 规范,比如 elevation、shadowColor、shadowOffset,在 OpenHarmony 上不一定有完全对应的底层实现。你过去在 Android 上调得很愉快的阴影,可能在 RK3568 上怎么看怎么不对劲。
这种差异决定了“拿代码跑一遍”只是起点,真正的工作在于逐个验证 UI 属性是否被正确消费。用一张小卡片做测试,成本最低,收效最快。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 从手绘线稿到布局结构:先画盒子再写组件
2.1 把“我觉得好看”翻译成可执行的盒子树
动手敲代码之前,我习惯先在一张白纸上画“盒子树”,把设计稿拆成没有视觉语言的层级关系。产品经理给的那张草图上,信息位置大概是:顶部一行放头像和姓名,中间放手机号、邮箱,底部是两个操作按钮。听上去已经很明确,但直接照着写代码还是会乱,因为你不清楚头部和中间信息区到底是共享一个容器,还是应该各自独立。
我最终拆出来的结构是这样:
code复制UserCard
├── HeaderRow
│ ├── Avatar(56x56,圆角裁成圆形)
│ └── UserMeta
│ ├── UserName
│ └── OrgName
├── Divider(细分隔线)
├── ContactRows
│ ├── ContactRow: Phone
│ └── ContactRow: Email
└── ActionRow
├── PrimaryButton(拨打电话)
└── GhostButton(发送消息)
这样拆分最大的好处是让数据的边界变得清楚。HeaderRow 渲染的是用户基础身份信息,ContactRows 渲染的是联系方式,ActionRow 承载的是业务操作。后续如果要在姓名旁边加一个“VIP 标识”,只需要在 UserMeta 内部扩展,不会影响其他区域。
2.2 为什么优先选 Flexbox 而不是绝对定位
很多新手在设计“右上角放一个图标”“底部按钮固定”这种需求时,第一反应是 position: 'absolute'。但在 OpenHarmony 这一层适配还没完全稳定的时候,我建议你尽量只用 Flexbox 把内容“弹”到目标位置,绝对定位只用于局部细节装饰。
原因是绝对定位依赖父容器坐标系,而在 RNOH 当前的适配实现里,容器尺寸上报和嵌套层级一旦多起来,坐标系偶尔会出现偏差。你用 Flexbox 的话,纵使某个样式属性映射不完美,最坏结果也只是间距偏大或对齐不齐,不会出现整块 UI 漂移的问题。
卡片在这里用的是最朴素的思路:外层 card 容器负责白底、圆角、内边距,内部从上到下排列三个区域;头部用横向 Flex,信息行也用横向 Flex,按钮行用 flexDirection: 'row' + gap 拉开间距。全部压力都给到 Flexbox,结构简单,表现也最稳定。
2.3 关于宽高的单位换算
React Nativ
