React Native for OpenHarmony 实战:三方库 react-native-popup-menu 的鸿蒙化适配指南
本文记录把 react-native-popup-menu 适配到 HarmonyOS 的完整过程。
这个库是目前遇到的最省事的一个:纯 JS、零运行时依赖、没有 prepare、main 指向的 rollup 产物与上游逐字节一致。接入几乎不需要动脑。
但它有一个很容易把断言写错的地方,值得单独拿出来讲:
同一个库里,导出组件的形态是混的 ——
MenuProvider/MenuContext是普通 class,
而Menu/MenuOption/MenuOptions/MenuTrigger全部被 HOC 包过(withCtx→React.forwardRef)
⇒typeof是object、没有可用的prototype。
我第一版按"都是 class"写断言,一口气错了 12 条。修正后 29 / 29 全部通过。

一、先说结论
| 项 | 结果 |
|---|---|
| 上游最新版 | 0.19.0;license: ISC;gitHead = 2ec80a8e38e2eb641eb2dd16950873f3fe0126cd |
| 库类型 | 纯 JS 组件库:MenuProvider + Menu + MenuTrigger + MenuOptions + MenuOption,外带 4 个渲染器 |
| 是否需要原生适配 | 不需要(无 harmony/、无 NativeModules) |
| 运行时依赖 | 零(dependencies 是空对象 {}) |
prepare / prepack | 都没有 ✓ |
prepublish | ⚠️ 有一个 prepublish: "yarn build",但实测在 npm 11.9.0 下不触发(install 与 pack 都不跑)⇒ 死脚本,而且 npm 元数据里也有同一行 ⇒ 上游自带 |
main | build/rnpm.js(rollup 的 UMD 产物,104 KB,已提交) |
| 与 npm 上游的差异 | 33 / 34 个文件逐字节一致;唯一差异是 package.json(含 src/** 20 个文件与 build/rnpm.js 产物) |
| 需要 HAR / 权限 / ohpm | ❌ 都不需要 |
| 编译 | assembleHap 3 分 36 秒 / 3 分 46 秒 |
| 设备侧断言 | ✅ 29 / 29 全部通过 |
| ★ 最有价值的结论 | 组件形态混用(class vs HOC 包装的 forwardRef);且 HOC 没有提升内层 class 的 propTypes ⇒ 那些校验根本不会执行 |
| ★ 实测行为 | 选中即关闭;onSelect 返回 false 则不关闭;背板点击关闭;返回键关闭(且不会退出应用) |
| 我自己的失误 | 按"都是 class"写断言(错 12 条);用 React state 读 isMenuOpen() 导致读到旧值 |
二、判定过程:最省事的一个库
| 步 | 做法 | 结果 |
|---|---|---|
| ① | package.json 里有没有 harmony.autolinking | 没有 |
| ② | 仓库里有没有 harmony/ | 没有 |
| ③ | 代码里有没有 NativeModules / requireNativeComponent | 全无 |
dependencies 是空对象 ⇒ 不需要补装任何传递依赖,安装路径最干净。
三、交付包:实现与产物双重零改动
3.1 逐文件比对(先去 CR 再逐字节比)
| 类别 | 结果 |
|---|---|
| 一致 | 33 个文件 |
| 不同 | 1 个:package.json |
| 交付包缺少 | 0 |
| 交付包多出 | 6 个:.gitignore、两个 README.OpenHarmony*、代码检查报告、spec.json、契约测试 |
★ 这里要分两层说"零改动":
src/**全部 20 个文件一致 ⇒ 没有偷偷改实现;build/rnpm.js(rollup 产物)也与上游逐字节一致 ⇒ 排除了"源码改了但产物没重打 / 产物陈旧"这类问题。
为什么要单独核对产物:这个库的
main指向build/rnpm.js,运行时真正执行的是产物。所以"逐文件 diff"里必须把它算进去;只看src/是不够的。
3.2 prepublish 实测:在 npm 11.9.0 下是"死脚本"
package.json 里有:
"scripts": { "build": "rollup -c …", "prepublish": "yarn build", "test": "node --test …", "lint": "eslint ." }
prepare / prepublish 这一族脚本会在安装时执行,而且能在包的目录里动手改产物 —— 本系列已经栽过两次(一次"打不出 tgz + 退出码 1",一次 rm -rf built 直接删掉自己的 main 目标)。而且它调的是 yarn,如果真在安装时跑、而消费者没有 yarn,安装就会失败。
所以在副本上实测(这类脚本可能改产物):
| 实验 | 结果 |
|---|---|
npm install(不加 --ignore-scripts) | exit 0、added 1 package;输出里没有 prepublish/yarn/rollup 任何字样;build/rnpm.js 完好 |
npm install --ignore-scripts(对照) | exit 0 |
npm pack --ignore-scripts | exit 0,产出 tgz |
npm pack(不加) | exit 0,产出 tgz;同样没有 prepublish 输出 |
⇒ prepublish 在 npm 11.9.0 下既不在 install 触发、也不在 pack 触发 ⇒ 它是死脚本,不构成交付缺陷。
教训:“有这个脚本” ≠ “这个脚本会跑”。npm 文档对
prepublish的描述改过多次,以实测为准。反过来说,在别的 npm 版本 / 别的安装路径上它可能真的会跑,所以--ignore-scripts仍值得作为默认。
3.3 问题
| 问题 | 说明 |
|---|---|
spec.json 缺 upstreamCommit | 而 npm 明确有 gitHead(2ec80a8e…)⇒ 属应修项 |
validation 是裸字符串 "pass" | 没有可复核的测试项清单 |
多发了 .claude/settings.local.json | 78 字节,是 AI 编程工具的本地配置,不该随包发布(工程卫生问题) |
| 契约测试是包级 smoke test | 只检查包名 / 版本 / 主入口 / 中文 README 存在,一次组件都没渲染过 |
四、接入方式
npm install "git+https://atomgit.com/oh-react-native/react-native-popup-menu.git#0.19.0-ohos-1.0.0" --ignore-scripts
// metro.config.js —— file: / 软链装法需要把真实目录加进 watchFolders
watchFolders: [ path.resolve(__dirname, '../react-native-popup-menu') ],
import PopupMenuTestApp from './PopupMenuTestApp';
AppRegistry.registerComponent('PopupMenuTestApp', () => PopupMenuTestApp);
hdc shell aa force-stop com.rnoh084.demo
hdc shell aa start -b com.rnoh084.demo -a EntryAbility --ps rnAppKey PopupMenuTestApp
不需要 HAR、权限、ohpm、link-harmony,也不需要补装任何依赖。
五、导出形态:这个库里 class 和 HOC 是混着的
5.1 源码里的导出
// src/index.js
export {
Menu as default, Menu, MenuProvider, MenuContext,
MenuOption, MenuOptions, MenuTrigger,
renderers, withCtx as withMenuContext,
};
const renderers = { ContextMenu, SlideInMenu, NotAnimatedContextMenu, Popover };
5.2 但运行时形态不一样(实测)
| 导出 | 源码写法 | 实测 typeof | 有无可用 prototype |
|---|---|---|---|
MenuProvider | export default class MenuProvider extends Component | function | ✅ 有(openMenu / closeMenu / toggleMenu / isMenuOpen) |
MenuContext | deprecatedComponent(…)(MenuProvider) ⇒ 返回一个 class | function | ✅ 有 |
Menu(default) | export default MenuExternal,而 MenuExternal 由 withCtx(...) 包出 | object | ❌ undefined |
MenuOption | export default withCtx(MenuOption) | object | ❌ |
MenuOptions | export default withCtx(MenuOptions) | object | ❌ |
MenuTrigger | export default withCtx(MenuTrigger) | object | ❌ |
withCtx = withContext(PopupMenuContext, 'ctx') —— 内部走 React.forwardRef(源码里有 if (!React.forwardRef) 的兼容分支)⇒ 返回的是对象,所以 typeof 不是 function、也没有 prototype。
⇒ 断言"这是 class"时必须区分对待,否则会像我一样一口气错 12 条。

5.3 顺带发现一个真实后果:这些 propTypes 不会被执行
MenuTrigger / MenuOptions / MenuOption 的 propTypes 是定义在内层 class 上的(源码里能读到),但导出给消费者的是外层 HOC 对象,而 withCtx 没有把 propTypes 提升上去:
typeof MenuTrigger.propTypes // 实测 'undefined'
typeof MenuOptions.propTypes // 实测 'undefined'
⇒ React 校验 propTypes 时读的是最终渲染的那个组件(这里是 forwardRef 对象)。它上面没有 propTypes ⇒ 这些校验根本不会运行。
影响:开发期少了属性类型提示(比如 MenuTrigger 的 text 写成 number 不会报警告)。库能跑,但"写了 propTypes"这件事没有生效。
5.4 Menu 上还有两个静态配置方法
Menu.setDefaultRenderer(renderer) // 改全局默认渲染器
Menu.setDefaultRendererProps(props)
它们的实现是直接改 menuConfig.defRenderer:
// src/config.js
export const menuConfig = { defRenderer: ContextMenu, defRendererProps: {} }
⇒ 改的是全局默认值,影响此后所有未显式指定 renderer 的 Menu(和某些库的 setMode 一样属于全局副作用)。
六、可测行为(都来自源码,不是猜的)
6.1 默认渲染器是 ContextMenu
// src/config.js
export const menuConfig = { defRenderer: ContextMenu, defRendererProps: {} }
⇒ 不传 renderer 时用的是 ContextMenu,不是 Popover。(renderers 一共 4 个:ContextMenu / SlideInMenu / NotAnimatedContextMenu / Popover。)
6.2 选中后是否关闭,由 onSelect 的返回值决定
// src/MenuOption.js
_onSelect() {
const { value } = this.props;
const onSelect = this.props.onSelect || this._getMenusOnSelect();
const shouldClose = onSelect(value) !== false; // ← 关键
…
}
⇒ onSelect 返回 false ⇒ 菜单不关闭;返回其它值(含 undefined)⇒ 关闭。
6.3 两条关闭路径
// src/MenuProvider.js
_handleBackButton = () => { if (this.isMenuOpen()) { this.closeMenu(); } }; // 返回键
_onBackdropPress = () => { … this.closeMenu(); }; // 点背板
⇒ 返回键能关菜单(MenuProvider 自己装了 BackHandler)、点背板也能关。
6.4 动画是原生驱动的
// src/constants.js
export const USE_NATIVE_DRIVER = (Platform.OS !== "web");
⇒ 鸿蒙(非 web)上 useNativeDriver 为真 ⇒ JS 侧读不到动画值、布局 dump 也读不到 transform。所以本轮把验证重点放在结构性证据上(菜单是否打开、选项文本是否出现、几何矩形、回调与 isMenuOpen()),而不追动画中间态。
七、实测:断言 29/29,行为四条全部成立
7.1 断言
| 组 | 内容 | 结果 |
|---|---|---|
| A 契约 | 导出形态(class vs HOC 对象)、$$typeof、Menu 的两个静态方法、renderers 4 个、MenuProvider.propTypes 4 键、propTypes 未被提升、MenuContext 是 class | 25/25 |
| B 开关与几何 | 触发器几何、isMenuOpen() 返回布尔 | 3/3 |
| C 回调与边界 | 事件记录格式 | 1/1 |
| 合计 | 29/29 |
7.2 命令式开关(通过 MenuProvider 的 ref)
OPEN 命令式 openMenu(m1)
OPEN m1 onOpen ← onOpen 触发
QUERY isMenuOpen() = false ← 打开前
QUERY isMenuOpen() = true ← 打开后
而布局 dump 里三个选项都渲染出来了:
OPT-ALPHA [81,1875,651,1924]
OPT-BETA [81,1954,651,2003]
OPT-GAMMA [81,2033,651,2082]
⇒ 选项间距恒为 79px(1954−1875 = 79,2033−1954 = 79),且三者左边界、高度完全一致 ⇒ 列表是规整排布的。
7.3 选中即关闭
点 OPT-BETA:
SELECT m1 onSelect(beta) ⇒ 返回 undefined ⇒ 应关闭
CLOSE m1 onClose
⇒ onSelect 收到的是选项的 value('beta'),随后 onClose 触发、选项从屏上消失 ✓
7.4 ★ 边界:onSelect 返回 false 时菜单不关闭
点 m2 的 OPT-ONE(它的 onSelect 故意 return false):
SELECT m2 onSelect(one) ⇒ 返回 false ⇒ 不应关闭
实测:选项仍然留在屏上 ✓✓ 源码语义完全成立。
这条对实际开发很有用:想做"多选""选完不关"的菜单,就让
onSelect返回false。
7.5 背板点击关闭
m2 仍开着时点屏幕空白处:
(选项从屏上消失)
⇒ 背板接收了这次点击并调用了 closeMenu() ✓
7.6 返回键关闭(且不退出应用)
先打开 m1,再按返回键:
CLOSE m1 onClose
(选项从屏上消失)
应用仍在后台栈中(未被退出)
⇒ MenuProvider 的 BackHandler 生效,且返回键被菜单消费掉、没有传下去把 Activity 关掉 ✓

八、我自己的两个失误
| # | 失误 | 后果 | 纠正 |
|---|---|---|---|
| 1 | 按"都是 class"写断言(对 Menu / MenuOption / MenuOptions / MenuTrigger 检查 prototype.render 等) | 一次错 12 条(实测 typeof 是 object、prototype 是 undefined) | 先读源码看导出写法、再用 typeof 实测确认;改成断言"被 HOC 包过的对象(typeof 'object' + $$typeof 存在 + 无可用 prototype)",并顺带发现 propTypes 没被提升 |
| 2 | 用 React state 读 isMenuOpen()(在同一个 tick 里先 setState 再断言) | 该条断言读到旧值而失败 | 改成实时调用 providerRef.current?.isMenuOpen?.(),不经过 state |
⇒ 两条都是测试写法问题,不是库的问题;修正后 29/29。

九、已知限制与本次验证边界
9.1 用这个库要知道的
| 事项 | 说明 |
|---|---|
Menu 必须在 MenuProvider 之下 | 否则构造函数直接 throw("Menu component must be ancestor of MenuProvider") |
| 组件形态混用 | MenuProvider / MenuContext 是 class;Menu / MenuOption / MenuOptions / MenuTrigger 是 HOC 包过的对象(typeof 'object') |
propTypes 不生效 | 它们挂在内层 class 上,HOC 没有提升 ⇒ React 不会校验 |
onSelect 返回 false 可阻止关闭 | 想做多选/连续操作时很有用 |
setDefaultRenderer 是全局副作用 | 改的是 menuConfig.defRenderer,影响此后所有未显式指定 renderer 的 Menu |
默认渲染器是 ContextMenu | 不是 Popover |
MenuContext 已废弃 | 用它会打印废弃警告,应改用 MenuProvider |
| 返回键会被菜单消费 | 菜单开着时按返回键只关菜单,不会退出页面/应用 |
9.2 本次验证的边界
- 只在一台模拟器上验证(
Pura X View,density 3,1320×2232),没有真机。 - 只验证了默认渲染器
ContextMenu;Popover/SlideInMenu/NotAnimatedContextMenu完全没测(它们的位置计算逻辑复杂,是最值得后续单独测的部分)。 renderOptionsContainer/optionsContainerStyle/customStyles自定义未测。MenuTrigger的disabled、onPress、openOnLongPress等 prop 未逐条测(只测了text能渲染出来)。- 多菜单同时打开 / 同名菜单(重名会
console.warn)未测。 - 动画中间态未测(
USE_NATIVE_DRIVER在鸿蒙为真,动画在原生侧,本轮不追)。 withMenuContextHOC 的用法未测;MenuContext只断言了形态,没实际用它开菜单。- 弹出的菜单位置是实测记录的,不是对照源码公式算出来的:本轮记录了"选项在触发器附近、三者间距恒 79px",没有把
ContextMenu的定位公式推导一遍再验证。 - 没有跨平台对照(未在 iOS/Android 上跑同一套用例)。
- 实测中观察到一次
isMenuOpen()在返回键关闭后返回undefined(同一时刻选项已消失、onClose已触发);未定性,如实记录。
未改动库代码。
十、常见问题
Q1:为什么 Menu.prototype.render 是 undefined?
因为它不是 class。源码里 Menu 的默认导出是 withCtx(Menu),而 withCtx 内部用 React.forwardRef ⇒ 返回对象(typeof 'object'),没有 prototype。
只有 MenuProvider 和 MenuContext 是真正的 class,能访问到原型方法。
Q2:那我怎么打开/关闭菜单?
两条路都可以:
// ① ref 命令式(推荐做自动化与外部控制)
<MenuProvider ref={ref} />
ref.current.openMenu('m1');
ref.current.closeMenu();
ref.current.isMenuOpen();
// ② 组件式
<Menu name="m1">
<MenuTrigger text="打开" />
<MenuOptions>
<MenuOption value="a" text="选项 A" />
</MenuOptions>
</Menu>
Q3:onSelect 的返回值有什么作用?
const shouldClose = onSelect(value) !== false;
返回 false ⇒ 菜单保持打开;返回其它任何值(包括不写 return)⇒ 选中后关闭。实测已确认(SELECT m2 onSelect(one) ⇒ 返回 false 之后选项仍在屏上)。
Q4:为什么我写的 propTypes 没生效?
因为它们是定义在内层 class 上的,而导出给消费者的是外层 HOC 对象,withCtx 没有把 propTypes 提升上去。实测:
typeof MenuTrigger.propTypes // 'undefined'
typeof MenuOptions.propTypes // 'undefined'
⇒ React 校验 propTypes 时读的是最终渲染的组件,它上面没有 ⇒ 不会执行校验。
Q5:默认用哪个渲染器?
ContextMenu(源码 config.js 里 defRenderer: ContextMenu),不是 Popover。要换:
<Menu renderer={renderers.Popover}>…</Menu>
// 或者改全局默认
Menu.setDefaultRenderer(renderers.SlideInMenu);
⚠️ setDefaultRenderer 改的是全局 menuConfig.defRenderer,影响此后所有未显式指定 renderer 的 Menu。
Q6:点空白处能关掉菜单吗?按返回键呢?
都能。 源码里:
_onBackdropPress ⇒ closeMenu()(点背板关闭);_handleBackButton:if (this.isMenuOpen()) this.closeMenu()(返回键关闭)。
实测确认:点屏幕空白处选项消失;按返回键选项消失且 onClose 触发,应用没有被退出。
Q7:Menu 报 Menu component must be ancestor of MenuProvider 怎么办?
字面意思:Menu 必须在 MenuProvider 的子树里。源码在 Menu 的构造函数里就直接 throw 了。把 <MenuProvider> 提到最外层即可。
Q8:MenuContext 还能用吗?
能用但已废弃——它是 deprecatedComponent(...) 包出来的,用旧 API(openMenu / toggleMenu / closeMenu / isMenuOpen)时会打印废弃警告。新代码请用 MenuProvider。
Q9:main 指向的是 build/rnpm.js,会不会拿到过期的产物?
这个交付包里不会 —— 实测 build/rnpm.js 与 npm 上游逐字节一致,src/** 也全部一致。但核对时必须把产物一起比,否则"源码一致"并不能保证"跑起来的产物一致"。
Q10:装的时候要注意什么?
几乎什么都不用注意:零运行时依赖、没有 prepare/prepack,那个 prepublish 实测是死脚本。本系列仍统一加 --ignore-scripts(零成本、最稳)。
小结
react-native-popup-menu 是目前遇到最省事的一个:纯 JS、零运行时依赖、没有 prepare、src/** 与 rollup 产物都与上游逐字节一致(33/34 个文件)。设备侧 29 / 29 断言全过,四条行为——选中即关闭、onSelect 返回 false 则不关闭、背板点击关闭、返回键关闭——全部实测成立。
值得记下来的是这几条:
-
同一个库里,导出组件的形态可能是混的。
MenuProvider/MenuContext是 class,而Menu/MenuOption/MenuOptions/MenuTrigger都是withCtx(→React.forwardRef)包出来的对象。⇒ 别按"组件就是 class"写断言,先读源码的导出写法、再用typeof实测确认。(我第一版因此一次错了 12 条。) -
HOC 不提升
propTypes,校验就静默失效。 这个库把propTypes定义在内层 class 上,而导出的是外层 HOC 对象 ⇒ React 根本不会执行这些校验。⇒ 看到"库里有 propTypes"不等于"真的会校验"。 -
main指向打包产物时,diff 必须包含产物。 这个库运行时执行的是build/rnpm.js;只比src/会漏掉"源码改了但产物没重打"。本轮产物也与上游一致,才算真的零改动。 -
“有这个脚本” ≠ “这个脚本会跑”。
prepublish: "yarn build"看着很危险(会改产物、还依赖yarn),但实测在 npm 11.9.0 下install与pack都不触发。⇒ npm 生命周期脚本一律实测,别按文档推断;同时--ignore-scripts仍值得作为默认。 -
用 React state 做同一 tick 的断言会读到旧值。 我有一版把
isMenuOpen()的结果写进 state 再在同一个回调里断言 ⇒ 读到打开前的值而失败。⇒ 验证类代码要实时取值,不要绕 state。
本篇用到的库
| 项 | 内容 |
|---|---|
| 三方库 | react-native-popup-menu(上游 0.19.0 的鸿蒙适配版) |
| 适配仓库 | https://atomgit.com/oh-react-native/react-native-popup-menu |
| 适配 TAG | 0.19.0-ohos-1.0.0 |
| 需要 HAR / 权限 / ohpm | 都不需要(纯 JS,零运行时依赖) |
| 库类型 | 纯 JS 组件库:菜单/弹出菜单(MenuProvider + Menu + 触发器等) |
| 运行时依赖 | 零(dependencies: {}) |
prepare / prepublish | 无 prepare;有一个 prepublish: "yarn build",实测不触发 |
| 许可证 | ISC |
| 上游仓库 | https://github.com/instea/react-native-popup-menu |
| 上游基线 | npm gitHead = 2ec80a8e38e2eb641eb2dd16950873f3fe0126cd |
| 宿主工程 | RNOH084Demo(测试页 rnAppKey = PopupMenuTestApp) |
# 从适配仓库安装
npm install "git+https://atomgit.com/oh-react-native/react-native-popup-menu.git#0.19.0-ohos-1.0.0" --ignore-scripts
# 或本地 file: 安装(装成软链,需要配 watchFolders)
npm install ../react-native-popup-menu --ignore-scripts
// metro.config.js
watchFolders: [ path.resolve(__dirname, '../react-native-popup-menu') ],
// 用法:MenuProvider 必须在最外层;Menu 必须在它之下
import Menu, {MenuProvider, MenuTrigger, MenuOptions, MenuOption, renderers} from 'react-native-popup-menu';
<MenuProvider ref={menuRef}>
<Menu
name="m1"
renderer={renderers.ContextMenu} // 默认就是 ContextMenu
onOpen={() => console.log('opened')}
onClose={() => console.log('closed')}
onSelect={(value) => {
console.log('selected', value);
// 返回 false ⇒ 选中后【不关闭】(适合多选/连续操作)
// 返回其它值(含 undefined)⇒ 选中后关闭
}}>
<MenuTrigger text="打开菜单" />
<MenuOptions>
<MenuOption value="alpha" text="选项 A" />
<MenuOption value="beta" text="选项 B" />
</MenuOptions>
</Menu>
</MenuProvider>;
// 命令式控制(ref 指向 MenuProvider)
menuRef.current?.openMenu('m1');
menuRef.current?.closeMenu();
menuRef.current?.isMenuOpen();
# 换页启动测试页(force-stop 不能省,换页参数只在冷启动生效)
hdc shell aa force-stop com.rnoh084.demo
hdc shell aa start -b com.rnoh084.demo -a EntryAbility --ps rnAppKey PopupMenuTestApp
验证环境
| 项 | 版本 |
|---|---|
| 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,263,324 字节) |
| 本次构建 | assembleHap 3 分 36 秒 / 改断言后重编 3 分 46 秒 |
| 验证规模 | 设备侧 29 / 29 断言;外部协议含命令式开/关、选中关闭、false 边界、背板关闭、返回键关闭各 1 次;上游 34 个文件逐字节比对;prepublish 4 组安装/打包实测 |
欢迎加入 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)