React Native for OpenHarmony 实战:三方库 react-native-loading-spinner-overlay 的鸿蒙化适配指南
本文记录把 react-native-loading-spinner-overlay 适配到 HarmonyOS 的完整过程。
这个库很小(两个源文件、约 3 KB),也很纯粹:一个全屏的加载遮罩,零运行时依赖、没有 prepare 脚本、连编译产物都与上游逐字符一致。接入本身毫无难度。
但它带来的验证问题比接入问题有意思得多:
- 它的所有渲染都在 RN 的
Modal里(transparent+statusBarTranslucent)⇒ 要测的是 RNOH 的 Modal + 半透明遮罩; - 遮罩一起,它就把页面上所有触摸都吞掉了 —— 这让我原本设计的"遮罩显示期间点按钮触发重渲染"的实验根本无法执行;
- 它是半受控的:
cancelable被返回键关闭后,组件内部认为已关闭、父组件的visible却还是true,而库没有任何回调告知父组件。
第 3 条是这轮最有价值的发现:它是一个真实的行为缺陷,而且只靠读源码 + 一个四步实测就能坐实。

一、先说结论
| 项 | 结果 |
|---|---|
| 上游最新版 | 3.0.1(MIT);gitHead = 84896fa0284b705f136622dcd0d7f17184f747bb |
| 库类型 | 纯 JS 函数组件,渲染在 RN 的 Modal 内 |
| 是否需要原生适配 | 不需要(无 harmony/、无 NativeModules) |
| 运行时依赖 | 零(dependencies 字段不存在) |
prepare / prepack | 都没有 ⇒ 安装路径干净 |
| 与 npm 上游的差异 | 11 / 12 个文件去掉 CR 后逐字符一致(含 src/** 与 lib/** 编译产物);唯一差异是 package.json |
| 编译 | assembleHap 3 分 52 秒;HAP 82,083,102 字节(+32,770) |
| 设备侧断言 | 12 / 14(A 10/10、B 1/1、C 1/1、D 0/2 未验证,原因见第八节) |
| ★ 外部实测(全部命中) | 遮罩文字 Y = 1281(几何预言逐像素吻合);rgba(0,0,0,0.25) 实测亮度 ×0.75;rgba(255,0,0,1) 全屏 (254,0,0)(含状态栏区域);遮罩吞掉全部页面触摸(有对照组) |
| ★ 一个真实的行为缺陷 | 半受控:cancelable 关闭后组件(false) 与父组件 prop(true) 长期不一致,且库不接受 onRequestClose、无任何回调 |
| ★ 未验证的一条 | 不传 spinnerKey 时"每次渲染都重挂载 Modal" —— 代码级事实成立,运行时挂载计数本轮没取到(原因正是第 5 节那条) |
一句话结论:库本身能用、几何与像素都对;但要记住它会吞掉页面所有交互,以及它的关闭是"半受控"的。
二、判定过程:三步走完,而且是这一系列里最干净的一个
| 步 | 做法 | 结果 |
|---|---|---|
| ① | package.json 里有没有 harmony.autolinking | 没有 |
| ② | 仓库里有没有 harmony/ | 没有 |
| ③ | 代码里有没有 NativeModules / requireNativeComponent | 全无 |
dependencies 字段直接不存在 ⇒ 零运行时依赖。
再补两项这个库特有的确认(这两项在前面的库里都出过事):
| 检查 | 结果 | 为什么值得单独查 |
|---|---|---|
scripts 里有没有 prepare / prepack | 都没有(只有 build / lint / test) | 有的库在 prepare 里会删掉随包发布的编译产物,导致安装失败、包静默损坏 |
| 入口在哪 | main: lib/index.js,lib/ 已提交 | 这类"入口是编译产物"的包要确认 lib/ 与 src/ 行为一致(否则你读的源码不是真正跑的东西) |
关于第二项的核实方式:这个包的 tsconfig.json 写的是 "target": "esnext" 且没有写 module ⇒ 编译产物是 ESM(import / export default)。这意味着在 PC 上用 Node require() 它是不行的,所以我没有做 PC 侧探针,而是直接读 lib/index.js 这份运行时真正执行的代码,并逐行核对它与 src/index.tsx 行为一致 ⇒ 排除"陈旧编译产物"这个风险。
三、交付包质量
3.1 与 npm 上游逐文件比对(先去 CR)
| 类别 | 结果 |
|---|---|
| 一致 | 11 个文件(src/**、lib/** 全部编译产物、README.md、LICENSE、tsconfig.json 等) |
| 不同 | 1 个:package.json |
| 交付包缺少 | 0 |
| 交付包多出 | 6 个:.gitignore、两个 README.OpenHarmony*、代码检查报告、spec.json、契约测试 |
实现与产物双重零改动,而且没有 prepare ⇒ 这是本系列里安装路径最干净的一个。
3.2 一个"看着像错、查证后没错"的地方
spec.json 里的上游地址写的是 git+ssh://git@github.com/...(SSH 形式)。第一眼像是不该这么写 —— 但查 npm 的 repository 字段,上游自己就是这么写的 ⇒ 不是缺陷。
教训:"名字/格式不一致"要先查数据源再定性。
3.3 问题
| 问题 | 说明 |
|---|---|
spec.json 缺 upstreamCommit | 而 npm 明确有 gitHead(84896fa0…)⇒ 属应修项 |
validation 是裸字符串 "pass" | 没有可复核的测试项清单 |
| 契约测试是包级 smoke test | 只检查包名 / 版本 / 主入口存在 / 中文 README 存在,一次组件都没渲染过 |
| 两个交付 README 都没写三件事 | ① 组件是半受控的;② 遮罩会吞掉页面所有触摸;③ 不传 spinnerKey 会重挂载 |
四、几何与像素:三条预言全部命中
4.1 遮罩文字的位置(逐像素吻合)
源码里 textContent 的样式是:
textContent: { fontSize: 20, fontWeight: 'bold', height: 50, top: 80 }
而它的容器是全屏绝对定位 + justifyContent: 'center'。
先算一遍(设备 density = 3,屏高 2232px):
文字上边 = 屏幕中心 − 文字半高 + top
= 2232/2 − (50vp/2 × 3) + (80vp × 3)
= 1116 − 75 + 240
= 1281
实测:Text [433,1281,887,1431] "SPIN-TEXT-DIM" ⇒ Y1 = 1281 ✓ 高度 150px 也正好是 50vp × 3 ✓
⇒ 这个库的布局在 RNOH 上与设计完全一致。
4.2 半透明遮罩的"变暗比例"(数值精确)
overlayColor 默认是 'rgba(0, 0, 0, 0.25)',作用在全屏容器上。在同一个像素位置比较"无遮罩 / 有遮罩":
| 位置(下面的页面元素) | 无遮罩 | 有遮罩 | 比值 |
|---|---|---|---|
(100,1700) 蓝色按钮 #1f6feb | (31,111,234) | (23,84,177) | 0.742 / 0.757 / 0.756 |
(660,1700) 页面背景 #0f1115 | (16,17,21) | (12,13,17) | 0.750 / 0.765 / 0.810 |
⇒ 实测比值 ≈ 0.75 = 1 − 0.25 ✓ 遮罩确实是"整体压暗 25%",而不是别的混合方式。
4.3 纯红遮罩顺带证实了 statusBarTranslucent
把 overlayColor 换成 'rgba(255, 0, 0, 1)':
| 采样点 | 实测 |
|---|---|
| (100,300) / (660,900) / (1200,2100) | (254,0,0) |
| (60,60) —— 状态栏区域 | (254,0,0) |
遮罩全屏铺满,连状态栏区域都被盖住 —— 这正好证实了源码里的:
<Modal … statusBarTranslucent={true}>
是真的生效的。


五、遮罩会吞掉页面所有触摸(带对照组)
这一条我先踩坑、后做对照才定性。
现象:遮罩显示后,用工具按坐标点页面上的按钮,工具报成功,但设备日志里没有任何对应的记录,遮罩也没关。
对照实验:
| 情形 | 结果 | 是否产生日志 |
|---|---|---|
| 无遮罩时点「显示 纯红遮罩」 | 红遮罩出现 | ✅ 有 |
| 遮罩在时点「隐藏全部遮罩」 | 无任何日志,遮罩仍在 | ❌ 无 |
⇒ Modal 窗口把页面所有触摸都吞掉了。
两个结论:
- 遮罩显示期间,用户点不到下面任何东西(这是 loading 遮罩的意图,但写代码时要意识到:"加载中禁止操作"是自动的,不需要额外加
pointerEvents); - ⚠️ 方法论:坐标点击工具报成功只代表"坐标被点到了",不代表按钮被按下。有东西盖着时它照样报成功。 以后凡是"点了没反应",都要先做一次"无遮挡时点同一个按钮"的对照。
六、cancelable 的真实触发源是返回键,不是点遮罩
源码里:
const close = () => { setSpinnerVisibility(false); };
const _handleOnRequestClose = () => { if (cancelable) { close(); } };
<Modal
onRequestClose={() => { _handleOnRequestClose(); }}
…
>
两个要点:
- 组件根本不接受
onRequestCloseprop —— 它内部只有一个私有的_handleOnRequestClose,从外面传什么都不起作用; - RN 的
Modal.onRequestClose由返回键 / 返回手势触发,不是点遮罩触发 ⇒cancelable必须用返回键来验。
实测:
| 实例 | 按返回键后 | 结论 |
|---|---|---|
cancelable 未设(= false) | 遮罩仍在 | ✓ 与 if (cancelable) 一致;且返回键没有把应用退出(被 Modal 消费了) |
cancelable = true | 遮罩关闭 | ✓ cancelable 经 Modal.onRequestClose 生效 |
⚠️ 别把
cancelable理解成"点遮罩可以关闭"。 它的实际含义是"允许返回键关闭"。
七、半受控语义:本轮最有价值的发现
7.1 源码
const [spinnerVisible, setSpinnerVisibility] = React.useState(visible); // ① 内部自己存一份
React.useEffect(() => { setSpinnerVisibility(visible); }, [visible]); // ② 只在 visible 变化时同步
const close = () => { setSpinnerVisibility(false); }; // ③ 关闭只改内部状态
⇒ cancelable 被返回键关闭时:只改了组件内部状态,没有通知父组件;而 useEffect 的依赖 [visible] 没变 ⇒ 不会重新同步。
7.2 四步实测(全部命中)
| 步骤 | 观测 | 结论 |
|---|---|---|
| ① 点「显示 cancelable」 | 遮罩出现(文字 Y = 1281) | 打开正常 |
| ② 按返回键 | 遮罩关闭;日志里没有父组件的新动作 | 父组件 prop 仍是 true |
③ 让父组件用同样的 visible={true} 重渲染 3 次 | 遮罩没有重新出现 | ✅ 边界坐实:组件(false) 与父组件(true) 长期不一致 |
④ 把 visible 走一次 false→true | 遮罩重新出现 | ✅ 与 [visible] 依赖一致 |
7.3 为什么这是个缺陷
- 库不提供任何回调告知父组件"我被关掉了"(它连
onRequestCloseprop 都不接受); - ⇒ 父组件无从得知。如果它一直保持
visible={true},就会长期处于"父组件以为在显示、实际已经关了"的不一致状态; - 而且遮罩不会自己回来,除非父组件主动把
visible走一次 false→true。
规避做法:
// 父组件自己掌握状态;要用 cancelable 就自己监听返回键
const [visible, setVisible] = useState(false);
useEffect(() => {
const sub = BackHandler.addEventListener('hardwareBackPress', () => {
if (visible) { setVisible(false); return true; } // 自己关,自己知道
return false;
});
return () => sub.remove();
}, [visible]);
<Spinner visible={visible} cancelable={false} textContent="加载中" />;

八、一条"代码级成立、运行时未验证"的行为
8.1 代码级事实
<View style={[styles.container, …]} key={spinnerKey || `spinner_${Date.now()}`}>
Date.now() 每次渲染都不同 ⇒ 不传 spinnerKey 时这个 key 每次渲染都变 ⇒ 按 React 语义,该子树会被卸载再重新挂载。这解释了 spinnerKey 这个 prop 为什么存在:想避免重挂载就得给一个稳定的 key。
8.2 为什么本轮没测到
我原本的设计是:传一个挂载时会打日志的 customIndicator,然后在遮罩显示期间点"重渲染"按钮,数挂载次数。
但这个设计被第 5 节推翻了:遮罩一起就吞掉所有触摸 ⇒ 我没法在遮罩显示期间点到页面按钮 ⇒ 父组件不会重渲染 ⇒ 挂载计数拿不到。
所以这一轮的 D 组两条断言如实失败:
✗ [D] 不传 spinnerKey 的实例挂载次数 > 1(每次渲染都重挂载)|期望 true|实际 false
✗ [D] 固定 spinnerKey 的实例挂载次数更少|期望 true|实际 false
· NO-KEY 挂载次数 = 0 FIXED-KEY 挂载次数 = 0
补测的正确做法:在页面里加一个自驱动计时器(遮罩显示期间自动触发父组件重渲染),这样就不依赖外部点击 —— 但这需要再改一次页面并重编。本轮为控制时长没有做。
⇒ 这一条只能记成"代码级事实成立、运行时未验证",不能写成"已实测"。
九、已知限制与本次验证边界
9.1 用这个库要知道的四件事
| 事项 | 说明 |
|---|---|
| 安装 | 无 prepare,普通 npm install 即可(本系列仍统一加 --ignore-scripts) |
| 遮罩会吞掉页面所有触摸 | 显示期间下面的按钮全点不到;也点不到遮罩来关闭 |
cancelable = 允许返回键关闭 | 不是"点遮罩关闭";而且不会通知父组件 |
| 半受控 | 组件自己关掉后,父组件的 visible=true 不会让它重开;要 false→true |
spinnerKey | 不给的话每次渲染都会重挂载 Modal 子树(代码级;运行时未验) |
不接受 onRequestClose prop | 想在关闭时做事情,只能自己在父组件监听返回键 |
9.2 本次验证的边界
- 只在一台模拟器上验证(
Pura X View,density 3,1320×2232),没有真机。 - 重挂载行为(D 组)未在运行时验证(原因见第八节)。
animation('none'/'slide'/'fade')完全未测 —— 本轮只用默认的'none';Modal 动画在 RNOH 上的表现未知。size='small'与数值型size未测(只用了默认'large');源码注释说不支持'normal',但没实测传'normal'会怎样。color(指示器颜色)未做像素核对(本轮只核对了遮罩色)。indicatorStyle/textStyle自定义未测。customIndicator/children自定义内容只用于挂载计数,没有渲染可测内容的布局/交互。- 多个 Spinner 同时
visible的叠加/层级未测(本轮六个实例每次只显示一个)。 children与customIndicator同时存在时的优先级未做组合实测(源码是children || _renderDefaultContent()、customIndicator || ActivityIndicator)。visible从 true→false 的关闭时序/动画未测。- 点遮罩本身是否有其它副作用未细测(已确认"不会关闭")。
- 没有跨平台对照(未在 iOS/Android 上跑同一套用例)。
未改动库代码。
十、常见问题
Q1:怎么接入?
npm install "git+https://atomgit.com/oh-react-native/react-native-loading-spinner-overlay.git#3.0.1-ohos-1.0.0" --ignore-scripts
// metro.config.js —— file: / 软链装法需要把真实目录加进 watchFolders
watchFolders: [ path.resolve(__dirname, '../react-native-loading-spinner-overlay') ],
import Spinner from 'react-native-loading-spinner-overlay';
<Spinner visible={loading} textContent="加载中…" />;
不需要 HAR、权限、ohpm、link-harmony。
Q2:遮罩显示时,我还能操作页面上的按钮吗?
不能。 它渲染在一个全屏的 Modal 窗口里,会吞掉页面所有触摸(实测:有遮罩时点页面按钮,设备日志里没有任何反应)。
这通常正是你要的效果(加载中禁止操作),但要知道:这个"禁止操作"是自动发生的,你不需要另外加 pointerEvents;反过来说,也别指望"点一下遮罩就能关掉它"。
Q3:cancelable 是不是"点遮罩可以关闭"?
不是。 cancelable 的真实含义是"允许返回键关闭":
const _handleOnRequestClose = () => { if (cancelable) { close(); } };
<Modal onRequestClose={() => _handleOnRequestClose()} …>
Modal.onRequestClose 由返回键/返回手势触发,点遮罩不会触发。实测:cancelable=false 时按返回键不关;cancelable=true 时按返回键关闭。
Q4:我想在遮罩被关闭时做点事情,可以传 onRequestClose 吗?
不行,这个组件根本不接受这个 prop —— 它内部只有一个私有的 _handleOnRequestClose。
Q5:我传了 visible={true},用户按返回键关掉之后,为什么它不再出现了?
因为它内部自己存了一份 visible 状态,cancelable 关闭时只改了内部状态:
const [spinnerVisible, setSpinnerVisibility] = useState(visible);
useEffect(() => setSpinnerVisibility(visible), [visible]);
useEffect 的依赖是 [visible],而父组件传的值一直是 true(没变) ⇒ 不会重新同步 ⇒ 遮罩保持关闭。实测已坐实:父组件用同样的 visible={true} 重渲染 3 次,遮罩也不会回来;只有把 visible 走一次 false→true 才会重新出现。
Q6:那正确的用法是什么?
父组件自己掌握状态,并且自己监听返回键(不要依赖库的内部行为):
const [visible, setVisible] = useState(false);
useEffect(() => {
const sub = BackHandler.addEventListener('hardwareBackPress', () => {
if (visible) { setVisible(false); return true; }
return false;
});
return () => sub.remove();
}, [visible]);
<Spinner visible={visible} cancelable={false} textContent="加载中…" />;
Q7:spinnerKey 是干什么的?
源码里那一行是:
key={spinnerKey || `spinner_${Date.now()}`}
不传 spinnerKey 时,key 每次渲染都不一样 ⇒ 按 React 语义,这个子树每次渲染都会被卸载再重新挂载(造成不必要的开销/闪烁)。给它一个固定字符串就能避免。
(⚠️ 这条是代码级事实;本轮的运行时挂载计数没能取到,原因见第八节,所以我没有把它写成"已实测"。)
Q8:遮罩的默认样式能改吗?
可以。overlayColor 改全屏底色、color 改指示器颜色、size 改指示器大小、textContent / textStyle 改文字、indicatorStyle 改指示器与文字容器的样式。
实测:overlayColor 默认 'rgba(0, 0, 0, 0.25)' 会把屏幕整体压暗到 75% 亮度;传 'rgba(255, 0, 0, 1)' 则整屏变纯红,连状态栏区域也盖住(因为 statusBarTranslucent 为 true)。
Q9:size 能传 'normal' 吗?
源码注释明确写着 size 不支持 'normal',类型是 'small' | 'large' | number。(本轮只实测了默认的 'large',传 'normal' 的实际表现未验证。)
Q10:遮罩打开后我卡住了,怎么把它弄掉?
cancelable=true的实例:按返回键;cancelable=false的实例:返回键关不掉(这是设计行为),页面按钮又被吞了 ⇒ 只能重启应用(aa force-stop+ 重新aa start)。
这是设计测试页时就要想好的事:有覆盖层的组件,每种状态都要有"退出来"的路,否则后续步骤会被卡死。
小结
react-native-loading-spinner-overlay 是一个很小、很干净的纯 JS 库:零运行时依赖、没有 prepare、11/12 个文件(含全部编译产物)与上游逐字符一致。几何与像素实测全部命中:遮罩文字位置误差 0 像素、rgba(0,0,0,0.25) 的压暗比例实测 ×0.75、纯红遮罩全屏 (254,0,0) 且覆盖状态栏。
值得记下来的是这几条:
-
"点了没反应"要先做无遮挡的对照。 遮罩一起,坐标点击工具照样报成功,但点击被 Modal 窗口吞掉、什么都没发生。⇒ 工具报成功 ≠ 按钮被按下;先分离"没点到"和"功能没生效"。
-
读源码要读运行时真正执行的那一份。 这个包
main指向 ESM 的编译产物(target: esnext且没写module),Node 端require不了 ⇒ PC 探针这条路走不通,只能直接读lib/并核对它与src/一致。这一步顺带排除了"陈旧编译产物"的风险。 -
cancelable这类 prop 要先确定"触发源"。 我第一版页面给组件传了onRequestClose—— 它根本不接受;而Modal.onRequestClose是返回键触发的,不是点遮罩。⇒ 写交互断言前先确认"这个交互由什么事件触发",否则会写出一个永远不会触发的断言。 -
"半受控"是这类组件的隐藏陷阱。 组件内部
useState(props.x)+useEffect([x])同步,同时又允许自己改这份状态 ⇒ 它一旦自己改了,父组件就被蒙在鼓里。⇒ 凡是组件内有useState(props.x),都要专门测"组件自己改了这份状态之后,父组件的 prop 还有效吗"。 这里的答案是:无效,而且库没有任何回调能通知你。 -
有覆盖层的组件,测试设计要预留"退出路径"。 遮罩吞触摸 ⇒ 页面按钮全失效 ⇒ 只能靠返回键或重启;而
cancelable=false的实例返回键也关不掉。⇒ 设计测试页时就要想好每种状态怎么退出来。 -
"代码级成立"和"已实测"是两件事。
key每次渲染都变 ⇒ React 必然重挂载,这是确定的语义;但我这一轮没能在运行时把挂载次数测出来(被遮罩吞触摸挡住了)。⇒ 如实写成"代码级事实成立、运行时未验证",而不是含糊地当成已验证。
本篇用到的库
| 项 | 内容 |
|---|---|
| 三方库 | react-native-loading-spinner-overlay(上游 3.0.1 的鸿蒙适配版) |
| 适配仓库 | https://atomgit.com/oh-react-native/react-native-loading-spinner-overlay |
| 适配 TAG | 3.0.1-ohos-1.0.0 |
| 需要 HAR / 权限 / ohpm | 都不需要(纯 JS,零运行时依赖) |
| 库类型 | 纯 JS 函数组件:全屏加载遮罩,渲染在 RN Modal 内 |
| 运行时依赖 | 零(dependencies 字段不存在) |
prepare / prepack | 都没有 ⇒ 安装路径干净 |
| 许可证 | MIT |
| 上游仓库 | https://github.com/joinspontaneous/react-native-loading-spinner-overlay |
| 上游基线 | npm gitHead = 84896fa0284b705f136622dcd0d7f17184f747bb |
| 宿主工程 | RNOH084Demo(测试页 rnAppKey = LoadingSpinnerTestApp) |
# 从适配仓库安装
npm install "git+https://atomgit.com/oh-react-native/react-native-loading-spinner-overlay.git#3.0.1-ohos-1.0.0" --ignore-scripts
# 或本地 file: 安装(装成软链,需要配 watchFolders)
npm install ../react-native-loading-spinner-overlay --ignore-scripts
// metro.config.js —— file: / 软链装法需要把真实目录加进 watchFolders
watchFolders: [ path.resolve(__dirname, '../react-native-loading-spinner-overlay') ],
// 用法:父组件自己掌握状态 + 自己监听返回键(不要依赖库的内部行为)
import Spinner from 'react-native-loading-spinner-overlay';
import {BackHandler} from 'react-native';
const [loading, setLoading] = useState(false);
useEffect(() => {
const sub = BackHandler.addEventListener('hardwareBackPress', () => {
if (loading) { setLoading(false); return true; }
return false;
});
return () => sub.remove();
}, [loading]);
<Spinner
visible={loading}
textContent="加载中…"
overlayColor="rgba(0, 0, 0, 0.25)" // 实测:屏幕亮度 ×0.75
color="#ffffff"
size="large" // 不支持 'normal';也可传数值
spinnerKey="main-spinner" // 建议给固定值,避免每次渲染重挂载
cancelable={false} // true 时允许返回键关闭(且不会通知父组件)
/>;
# 换页启动测试页(force-stop 不能省,换页参数只在冷启动生效)
hdc shell aa force-stop com.rnoh084.demo
hdc shell aa start -b com.rnoh084.demo -a EntryAbility --ps rnAppKey LoadingSpinnerTestApp
验证环境
| 项 | 版本 |
|---|---|
| React Native | 0.84.1 |
| React | 19.2.3 |
| RNOH(npm / ohpm) | @react-native-oh/react-native-harmony / @rnoh/react-native-openharmony 0.84.3 |
| Node.js / npm | v24.14.0 / 11.9.0 |
| DevEco Studio | 26.0.0.621 |
| HarmonyOS SDK | API 26(26.0.0.32) |
| 设备 | HarmonyOS 7.0.0(26.0.0) Beta2 模拟器 Pura X View(ohos-x64),1320×2232,density 3 |
| 宿主 HAP 产物 | entry-default-signed.hap(82,083,102 字节) |
| 本次增量构建 | assembleHap 3 分 52 秒,HAP +32,770 字节;打包资源 14(无新增,符合预期) |
| 验证规模 | 设备侧 12 / 14(A 10/10、B 1/1、C 1/1、D 0/2 未验证);外部含几何逐像素核对 1 次、像素取样 7 点、吞触摸对照 2 组、返回键 2 例、半受控四步、上游 12 个文件逐字符比对 |
欢迎加入 CPF-RN 鸿蒙社区:https://atomgit.com/CPF-RN
React Native for OpenHarmony 组织:https://atomgit.com/oh-react-native
RN 三方库鸿蒙适配清单:https://atomgit.com/oh-react-native/rn-ohos-adaptation-overview
更多推荐



所有评论(0)