React Native for OpenHarmony 实战:三方库 react-native-mask-input 的鸿蒙化适配指南
本文记录把 react-native-mask-input(输入框掩码)适配到 HarmonyOS 的完整过程。
它做的事:给 TextInput 套一层掩码 —— 输入 25122024 自动变成 25/12/2024,并同时给出"带掩码 / 不带掩码 / 混淆后"三种结果。
结论:完全可用,而且这是这几轮里"判据最强"的一个库 —— 因为它把核心逻辑抽成了三个纯函数:
formatWithMask、createNumberMask、Masks。这些函数不需要设备、不需要网络、不受平台差异影响,
我把它们逐条断言下来:26 条 PASS、1 条 FAIL(那 1 条是我自己把掩码写短了一位)。
★★★★★ 一、它的结构:一个组件 + 三个纯函数
src/index.tsx(524 B):
export {default as formatWithMask} from './formatWithMask';
export {default as createNumberMask} from './createNumberMask';
export {default as Masks} from './Masks';
export {default as useMaskedInputProps} from './useMaskedInputProps';
export default MaskInput;
| 导出 | 类型 | 作用 |
|---|---|---|
MaskInput(默认) | React.forwardRef(...) ⇒ typeof 是 object | 掩码输入框 |
formatWithMask | function(纯函数) | 核心格式化:{text, mask} → {masked, unmasked, obfuscated} |
createNumberMask | function(工厂) | 返回一个 (value) => MaskArray 的函数 |
Masks | object | 12 个预定义掩码 |
useMaskedInputProps | function(hook) | 组件内部用它算 props |
实测(按源码写断言,一次全中):
NOTE | 默认导出 MaskInput 的 typeof = object
PASS | ★★ 默认导出是 object(forwardRef 的结果,不是函数)
NOTE | MaskInput.$$typeof = Symbol(react.forward_ref)
PASS | ★★ $$typeof = Symbol(react.forward_ref)
PASS | ★ forwardRef 结果没有 prototype.render
PASS | ★★ formatWithMask 是 function(纯函数)
PASS | ★★ createNumberMask 是 function(工厂)
PASS | ★★ useMaskedInputProps 是 function(hook)
PASS | ★★ Masks 是 object(预定义掩码集合)
NOTE | Masks 的键数 = 12
NOTE | Masks 的键 = BRL_CAR_PLATE, BRL_CNPJ, BRL_CPF, BRL_CPF_CNPJ, BRL_CURRENCY, BRL_PHONE,
CREDIT_CARD, DATE_DDMMYYYY, DATE_MMDDYYYY, DATE_YYYYMMDD, USA_PHONE, ZIP_CODE
这里有个方法论的价值:这几轮我连续在"契约断言"上写错过(一次凭默认值猜、一次把
forwardRef当函数)。
这一轮先把源码里的导出语句抄下来再写断言 ⇒ 11 条一次全过 ✓
★★★★★ 二、formatWithMask:11 条判据,覆盖它的全部行为分支
源码(2539 B)的核心是一个 while 循环,三种 mask 元素走三条不同分支:
if (maskChar === valueChar) { … } // 值刚好等于掩码字符
else if (typeof maskChar === 'object') { // RegExp 或 [RegExp]
const shouldObsfucateChar = Array.isArray(maskChar); // ★ 数组形式才混淆
…
masked += valueChar;
obfuscated += shouldObsfucateChar ? obfuscationCharacter : valueChar;
unmasked += unmaskedValueChar;
} else { // 固定字符(string)
masked += maskChar;
obfuscated += maskChar; // ★ 固定字符不混淆
}
实测判据(按这个分支结构设计):
| # | 输入 | 期望 | 实测 |
|---|---|---|---|
| 1 | {text:'', mask} | 三个都是 '' | ✅ {"masked":"","unmasked":"","obfuscated":""} |
| 2 | {text:'abc', mask:undefined} | 三个都等于原文 | ✅ {"masked":"abc","unmasked":"abc","obfuscated":"abc"} |
| 3 | {text:'25122024', mask:日期掩码} | masked='25/12/2024' | ✅ 25/12/2024 |
| 4 | 同上 | unmasked='25122024' | ✅ 25122024 |
| 5 | 同上 | obfuscated 与 masked 相同(普通 RegExp 不混淆) | ✅ 25/12/2024 |
| 6 | {text:'1234', mask:[[/\d/],[/\d/],'-',[/\d/],[/\d/]]} | masked='12-34' | ✅ 12-34 |
| 7 | 同上 | obfuscated='**-**'([RegExp] 混淆、固定字符 - 保留) | ✅ **-** |
| 8 | 同上 + obfuscationCharacter:'#' | obfuscated='##-##' | ✅ ##-## |
| 9 | {text:'15/10', mask:日期掩码, maskAutoComplete:true} | masked='15/10/'(补固定字符) | ✅ 15/10/ |
| 10 | 同上但 maskAutoComplete 默认 | masked='15/10'(不补) | ✅ 15/10 |
| 11 | {text:'2a5', mask:[/\d/,/\d/]} | masked='25'(非匹配字符被跳过、不消耗 mask 位) | ✅ 25 |
⇒ 11 条全部命中 ✓✓ 其中第 7 条最能说明细节:
NOTE | [RegExp] 混淆结果 = {"masked":"12-34","unmasked":"1234","obfuscated":"**-**"}
⇒ [RegExp](数组形式)会被混淆成 obfuscationCharacter(默认 *),而固定字符 - 原样保留 ✓
⇒ 这正是"掩码库"最容易做错的细节(很多人会以为"所有数字都该混淆")
唯一一条 FAIL:是我把掩码写短了一位
我构造了一个"按值动态返回不同掩码"的函数掩码:
const fnMask = (value) => value.length > 3
? [/\d/, /\d/, /\d/, '.', /\d/] // ★ 只定义了 1 位小数
: [/\d/, /\d/, /\d/];
formatWithMask({text: '12345', mask: fnMask})
实测:
NOTE | mask 为函数的结果 = {"masked":"123.4","unmasked":"1234","obfuscated":"123.4"}
FAIL | ★★ mask 可以是函数,且按值动态返回不同掩码 | 期望=123.45 | 实际=123.4
逐位走一遍算法就明白了:掩码是 5 项 [d,d,d,'.',d],
'1','2','3' 占前三位、'.' 是固定字符、'4' 占第 5 位 ⇒ mask 用完就 break ⇒
第 6 个字符 '5' 无处可放 ⇒ 123.4 是正确结果 ✓
⇒ ⇒ 所以这条 FAIL 是我断言写错了,不是库的问题 ✓
⇒ 但"mask 可以是函数"这件事本身仍然成立(实测它确实被调用、并按其返回值工作)✓
⇒ 教训:写"函数掩码"的用例时,掩码长度要和输入长度匹配 —— 我下意识以为"多给一个字符它自己会扩展",但这个库是严格按掩码数组走的 ✓
★★★★ 三、createNumberMask:4 条判据,含一条"公式级"断言
源码(1268 B)返回一个函数:
export default function createNumberMask(props) {
const {delimiter = '.', precision = 2, prefix = [], separator = ','} = props || {};
return (value) => {
const numericValue = value?.replace(/\D+/g, '') || '';
let mask = numericValue.split('').map(() => /\d/);
if (mask.length > precision && !!separator) mask.splice(-precision, 0, separator);
const amountOfDelimiters = Math.ceil((numericValue.length - precision) / 3) - 1;
… mask.splice(delimiterPosition, 0, delimiter) …
return [...prefix, ...mask];
};
}
我按源码把这个公式算了一遍:value='123456'、默认参数
- 初长 = 6(6 位数字 ⇒ 6 个
/\d/) - 插
separator(-2位置)⇒ 7 项 amountOfDelimiters = ceil((6-2)/3) - 1 = ceil(4/3)-1 = 2-1 = 1⇒ 再插 1 个delimiter⇒ 8 项- 加上
prefix ['R','$',' ']的 3 项 ⇒ 11 项
实测:
NOTE | createNumberMask(...) 的 typeof = function
PASS | ★★ createNumberMask 返回一个函数
NOTE | factory("123456") 的结果 = ["R","$"," ",{},".",{},{},{},",",{},{}]
NOTE | 结果长度 = 11
PASS | ★★ 调用后返回数组(MaskArray)
PASS | ★★★ 长度符合公式:8 + prefix 3 = 11 ← ★ 公式级断言命中
NOTE | factory("") 的结果 = ["R","$"," "]
PASS | ★★ 空值 ⇒ 只剩 prefix(3 项)
NOTE | factory("R$ 99.99") 的结果(只取数字 9999)= ["R","$"," ",{},{},",",{},{}]
PASS | ★★ 只保留数字
⇒ 长度 11 与公式推导完全一致 ✓✓
⇒ 而且能看到内部结构:["R","$"," ",/\d/,".",/\d/,/\d/,/\d/,",",/\d/,/\d/]
(prefix 3 项 + 数字 1 位 + . + 3 位 + , + 2 位 = 11 ✓ 与 precision:2 / separator:',' / delimiter:'.' 完全对应)
★★★ 四、组件渲染与两条无害的 ARK 侧警告
组件本身很简单(src/MaskInput.tsx 999 B):
export default React.forwardRef(function (props, ref) {
const {mask, value, onChangeText, placeholderFillCharacter = '_', …} = props;
const maskedInputProps = useMaskedInputProps({…});
return <TextInput placeholder={maskedInputProps.placeholder} {…rest}
selection={…} value={…} onChangeText={…} ref={ref} />;
});
⇒ placeholderFillCharacter 默认 '_' ⇒ placeholder 会被替换成掩码形状(如 __/__/____)
实测:两个 TextInput 都正常渲染(y=1168 / y=1481),LogBox 无通知 ✓
⚠️ 但我没能在布局 dump 里找到 placeholder 文本(无论是当作 TextInput# 的标签还是独立的 Text# 节点)
⇒ 所以"placeholder 显示成掩码形状"这一条本轮未验证,如实记录 ✓
hilog 里有 2 条 ARK 侧警告:
W A0beef/#RNOH_ARK: This is usually not a problem and the application should continue to work normally.
TypeError: Cannot read property getWindowName of undefined
⇒ 注意它自己的前缀:“This is usually not a problem and the application should continue to work normally”
⇒ 功能未受影响(页面渲染、纯函数判据、输入框都正常)⇒ 如实记录为"ARK 侧警告、无功能影响" ✓
★★★ 五、其余预检结论
| 预检项 | 结果 |
|---|---|
dependencies | ✅ 空 |
peerDependencies | ✅ 只有 react / react-native ⇒ 无原生 peer |
老写法九项 + ListView / ViewPropTypes / Text.propTypes / measure / onLayout / useNativeDriver / NativeModules / Platform.OS / isRequired | ✅✅ 全部为空(用真实使用形态扫的) |
| 外部 import | 只有 react + react-native ✓ |
| 交付包形态 | ✅ src/(10 个 ts/tsx)+ lib/commonjs + lib/module + lib/typescript ⇒ 源码/产物/类型齐全 ✓ |
scripts.prepare | ⚠️ bob build ⇒ 安装必须 --ignore-scripts |




六、接入与预检(要点)
# ★ 必须 --ignore-scripts:它的 scripts.prepare 是 "bob build"
npm install "git+https://atomgit.com/oh-react-native/react-native-mask-input.git#1.2.3-ohos-1.0.0" --ignore-scripts
# 它没有 dependencies ⇒ 不需要补装任何东西
七、交付包质量与基线说明
| 类别 | 结果 |
|---|---|
| 交付包内容 | src/(10 个 ts/tsx)+ lib/commonjs + lib/module + lib/typescript ⇒ 源码、编译产物、类型声明三者齐全 ✓(71 文件) |
spec.json | ⚠️ 缺 upstreamCommit |
validation | ⚠️ "build-pass-device-pending" |
| ⚠️ 声明的基线 | reactNative: "0.88.0" + rnoh: "0.84.4" ⇒ 两字段自相矛盾 |
| 备注 | 库代码零改动(本轮未修改库任何文件) |
关于基线:本次验证在 RN 0.84.1 + RNOH 0.84.3 上完成。
纯函数判据(26 条)与平台完全无关 ⇒ 结论跨基线 100% 成立 ✓
八、已知限制与本次验证边界
8.1 用这个库要知道的
| 事项 | 说明 |
|---|---|
| ★★★★★ 三个纯函数可独立使用 | formatWithMask / createNumberMask / Masks —— 不需要组件、不需要设备 |
★★★★★ [RegExp] 数组形式才会混淆 | 普通 RegExp 不混淆;固定字符(string)永远不混淆 |
★★★★ maskAutoComplete 控制"值用完后是否补固定字符" | 默认 false |
★★★★ createNumberMask 返回函数,长度按公式 | 8 + prefix 项数(123456 + 默认参数 + 3 项 prefix ⇒ 11) |
★★★ MaskInput 是 forwardRef | typeof 是 object、$$typeof 是 Symbol(react.forward_ref) ⇒ 别当函数 |
★★★ Masks 有 12 个预定义掩码 | BRL_CAR_PLATE / BRL_CNPJ / BRL_CPF / BRL_CPF_CNPJ / BRL_CURRENCY / BRL_PHONE / CREDIT_CARD / DATE_DDMMYYYY / DATE_MMDDYYYY / DATE_YYYYMMDD / USA_PHONE / ZIP_CODE |
| ★★ 掩码是"严格按数组走"的 | 值比掩码长 ⇒ 多出的字符被丢弃(不会自动扩展) |
★★ placeholderFillCharacter 默认 '_' | 输入框空时 placeholder 会显示成掩码形状 |
★ scripts.prepare 会跑 bob build | 安装必须 --ignore-scripts |
8.2 本次验证的边界
- ★★★ 未验证"placeholder 显示成掩码形状"(没能从布局 dump 里找到 placeholder 文本);
- ★★★ 未验证真实输入时的掩码行为(未做输入注入;全部判据走纯函数);
- ★★ 未验证
selection的受控行为(光标位置维护,这通常是掩码库最难的部分); - ★★ 未验证
showObfuscatedValue的组件级效果(只验证了纯函数的obfuscated输出); - ★★ 未验证
Masks里 12 个预定义掩码各自的实际输出(只枚举了键名); - 未验证
useMaskedInputProps单独使用; - 未验证 粘贴长文本、删除字符、光标中点插入等边界;
- 未在
RN 0.88.0/RNOH 0.84.4上复验; - 未测其它屏幕宽度;未做跨平台对照。
库代码未改动。
九、常见问题
Q1:它在 RN 0.84 上能跑吗?
能,而且判据最强。 11 条契约全 PASS(含 forwardRef 的 $$typeof);
formatWithMask 12 条里 11 条 PASS(1 条是我掩码写短了);createNumberMask 4 条全 PASS(含公式级断言);
LogBox 无通知;两个掩码输入框正常渲染。
Q2:[RegExp] 和 RegExp 有什么区别?
RegExp(如/\d/)⇒ 校验通过后masked与obfuscated都是原字符(不混淆)[RegExp](如[/\d/])⇒obfuscated会被换成obfuscationCharacter(默认*)- 固定字符(string) ⇒ 永远原样出现在
masked与obfuscated里
实测:{text:'1234', mask:[[/\d/],[/\d/],'-',[/\d/],[/\d/]]} ⇒
masked='12-34'、obfuscated='**-**'(- 保留)✓
Q3:maskAutoComplete 是什么?
控制"值用完之后是否继续补固定字符"。
{text:'15/10', mask:日期掩码, maskAutoComplete:true} ⇒ '15/10/'(补了末尾 /);默认 false ⇒ '15/10'。
Q4:createNumberMask 怎么用?
const mask = createNumberMask({delimiter: '.', precision: 2, prefix: ['R', '$', ' '], separator: ','});
mask('123456'); // 返回一个 11 项的 MaskArray(3 项 prefix + 8 项数字/分隔符)
然后把这个函数直接当 mask 传给 MaskInput:
<MaskInput mask={createNumberMask({prefix: ['R', '$', ' ']})} />
Q5:值比掩码长会怎样?
多出的字符会被丢弃(掩码是严格按数组走的,不会自动扩展)。
我实测时就踩了这个:掩码只定义 1 位小数 [/\d/,/\d/,/\d/,'.',/\d/],输入 '12345' ⇒ 结果 '123.4'(5 被丢弃)✓
Q6:MaskInput 是组件还是对象?
是 forwardRef 的结果 ⇒ typeof 是 object:
import MaskInput, {formatWithMask} from 'react-native-mask-input';
typeof MaskInput; // 'object'
String(MaskInput.$$typeof); // 'Symbol(react.forward_ref)'
typeof formatWithMask; // 'function'(纯函数)
typeof Masks; // 'object'(12 个预定义掩码)
Q7:hilog 里 getWindowName of undefined 要紧吗?
那是 ARK 侧的警告,且它自己的文本就写着
"This is usually not a problem and the application should continue to work normally"
—— 实测功能未受影响(页面渲染、纯函数判据、输入框都正常)✓
LogBox 上也没有通知(说明它没进 JS 侧的 LogBox)。
小结
react-native-mask-input 是输入框掩码库:一个 forwardRef 组件 + 三个可独立调用的纯函数
(formatWithMask / createNumberMask / Masks)。dependencies 为空、老写法九项全空、零原生依赖。
最值得记下来的是这几条:
-
★★★★★ 三个纯函数 = 26 条零设备依赖的判据,这是本轮最大的价值。
formatWithMask12 条(覆盖它的全部分支:固定字符 /RegExp/[RegExp]混淆 /maskAutoComplete/ 非匹配字符跳过)createNumberMask4 条(含公式级断言:长度 11 = 8 + prefix 3)
⇒ 这些结论与平台、与基线、与网络全都无关 ⇒ 跨环境 100% 成立 ✓✓
-
★★★★★ 先把源码里的"形态事实"抄下来,再写断言 —— 11 条契约一次全过。
这几轮我连续在契约断言上写错过(一次凭默认值猜、一次把forwardRef当函数)。
这次先读了export default React.forwardRef(...)⇒ 直接断言typeof === 'object'+$$typeof === Symbol(...)⇒ 全中 ✓
⇒ 这是可复用的流程改进:断言前先抄源码。 -
★★★★
[RegExp]数组形式才混淆、固定字符永不混淆 —— 这是掩码库最容易做错的细节,
实测{mask:[[/\d/],[/\d/],'-',[/\d/],[/\d/]], text:'1234'}⇒obfuscated = '**-**'(-保留)✓ -
★★★★ 我唯一那条 FAIL 是"掩码写短了一位"。
掩码[/\d/,/\d/,/\d/,'.',/\d/]只有 1 位小数 ⇒ 输入'12345'时第 6 个字符被丢弃 ⇒'123.4'是正确行为 ✓
⇒ 教训:写"函数掩码"用例时,掩码长度必须与输入长度匹配 —— 别下意识以为它会自动扩展。 -
★★★
Masks的 12 个键本身就是一份有用的清单(BRL_*五个、DATE_*三个、CREDIT_CARD、USA_PHONE、ZIP_CODE、BRL_CAR_PLATE)✓ -
★★★ ARK 侧警告要读它自己的前缀。 那两条
getWindowName of undefined自带
"This is usually not a problem…"的说明,且功能未受影响、LogBox也没有 ⇒ 归为"无害" ✓ -
★★ 诚实标注没验证到的东西:placeholder 显示成掩码形状这一条我没能从 dump 里找到证据,
所以只写在"未验证"里,没有当成结论 ✓
本篇用到的库
| 项 | 内容 |
|---|---|
| 三方库 | react-native-mask-input(上游 1.2.3 的鸿蒙适配版) |
| 适配仓库 | https://atomgit.com/oh-react-native/react-native-mask-input |
| 适配 TAG | 1.2.3-ohos-1.0.0 |
| 需要 HAR / 权限 / ohpm | 都不需要(纯 JS) |
| 库类型 | 输入框掩码(格式化 / 反格式化 / 混淆) |
| 运行时依赖 | ✅ dependencies 为空;peer 只有 react / react-native |
| 导出形态 | 默认导出 MaskInput(forwardRef ⇒ typeof 为 object) + 4 个具名导出 |
⚠️ scripts.prepare | bob build ⇒ 安装需 --ignore-scripts |
| 许可证 | MIT |
| 上游仓库 | https://github.com/CaioQuirinoMedeiros/react-native-mask-input |
| 宿主工程 | RNOH084Demo(测试页 rnAppKey = MaskInputTestApp) |
npm install "git+https://atomgit.com/oh-react-native/react-native-mask-input.git#1.2.3-ohos-1.0.0" --ignore-scripts
import MaskInput, {formatWithMask, createNumberMask, Masks} from 'react-native-mask-input';
// ① 组件用法
<MaskInput
mask={[/\d/, /\d/, '/', /\d/, /\d/, '/', /\d/, /\d/, /\d/, /\d/]}
onChangeText={(masked, unmasked) => console.log(masked, unmasked)}
placeholder="DD/MM/YYYY"
/>
// ② 纯函数用法(无需渲染,最适合做判据 / 单测)
formatWithMask({text: '25122024', mask: [/\d/,/\d/,'/',/\d/,/\d/,'/',/\d/,/\d/,/\d/,/\d/]});
// ⇒ {masked: '25/12/2024', unmasked: '25122024', obfuscated: '25/12/2024'}
formatWithMask({text: '1234', mask: [[/\d/],[/\d/],'-',[/\d/],[/\d/]]});
// ⇒ {masked: '12-34', unmasked: '1234', obfuscated: '**-**'} ← 数组形式才混淆
createNumberMask({delimiter: '.', precision: 2, prefix: ['R','$',' '], separator: ','})('123456');
// ⇒ 11 项 MaskArray
// ⚠️ MaskInput 是 forwardRef ⇒ typeof 是 'object',不是 'function'
// ⚠️ 掩码严格按数组走:值比掩码长 ⇒ 多出的字符被丢弃(不会自动扩展)
// ⚠️ [RegExp] 才混淆;普通 RegExp 与固定字符都不混淆
// ⚠️ 安装必须 --ignore-scripts(prepare = bob build)
# 换页启动测试页 —— force-stop 不能省
hdc shell aa force-stop com.rnoh084.demo
hdc shell aa start -b com.rnoh084.demo -a EntryAbility --ps rnAppKey MaskInputTestApp
判据的复现方式
# ① 契约 + 纯函数判据(26 条 PASS + 1 条我自己算错)
hdc shell "hilog -x | grep mki-test" | Select-String 'PASS|FAIL|SUMMARY|NOTE'
# ⇒ formatWithMask 的 12 条(含 **-** 混淆、maskAutoComplete)
# ⇒ createNumberMask 的公式级断言(长度 11 = 8 + prefix 3)
# ② 12 个预定义掩码的键名
hdc shell "hilog -x | grep 'Masks 的键'"
验证环境
| 项 | 版本 |
|---|---|
| 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 |
| 本机状态栏高度 | 117px = 39vp |
| 宿主依赖 | ✅ 无需额外依赖(dependencies 为空) |
| 宿主 HAP 产物 | entry-default-signed.hap |
| 本次构建 | assembleHap 3 分 39 秒 ⇒ 一次成功(打包与构建退出码都检查了) |
| 验证规模 | 契约 11 条全 PASS;formatWithMask 11/12 PASS(1 条是我掩码写短);createNumberMask 4/4 PASS(含公式级断言);Masks 12 个键枚举;2 个输入框正常渲染;LogBox 无通知;hilog 有 2 条无害的 ARK 侧警告;4 张截图互异 |
⚠️ 基线说明:交付包
spec.json声明RN 0.88.0 + RNOH 0.84.4(两字段自相矛盾),本次验证在RN 0.84.1 + RNOH 0.84.3上完成。
纯函数判据与平台完全无关 ⇒ 结论跨基线 100% 成立 ✓
相关社区与项目地址
| 项目 | 地址 |
|---|---|
| React Native 鸿蒙官方社区(CPF-RN) | https://atomgit.com/CPF-RN |
| RNOH 框架仓库 | https://atomgit.com/openharmony-RN/ohos_react_native |
| RNOH 三方库使用文档 | https://atomgit.com/OpenHarmony-RN/usage-docs |
| React Native for OpenHarmony 组织 | https://atomgit.com/oh-react-native |
| RN 三方库鸿蒙适配清单 | https://atomgit.com/oh-react-native/rn-ohos-adaptation-overview |
欢迎加入 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)