本文记录把 react-native-notification(Toast 式轻提示)适配到 HarmonyOS 的完整过程。

它做的事很小:屏幕底部弹出一条深灰色的小提示,淡入 → 停一会儿 → 淡出。全部代码 105 行(2189 字节),零依赖。

它踩的坑也很典型,而且和之前几种都不一样——这次是从 react 里 import PropTypes:

import React, {
  Component,
  PropTypes,          // ← L3
} from 'react';

const propTypes = {
  timeout: PropTypes.number,     // ← L15:模块作用域求值
  fadeTime: PropTypes.number,
  minOpacity: PropTypes.number,
  maxOpacity: PropTypes.number,
  message: PropTypes.string,
};

PropTypes 早已从 react 里移出(React 15.5 起改到独立的 prop-types 包)⇒ 在 React 19 上 React.PropTypes 是 undefined ⇒ PropTypes.number 在模块作用域就抛错。

实测(点页面上的"尝试 require 该库"):

require('react-native-notification')  ⇒  require 成功,typeof = undefined

(同一时刻 LogBox)
Uncaught Error
Cannot read property 'number' of undefined          ← ★ 全新的错误特征
Stack: anonymous → loadModuleImplementation → guardedLoadModule → metroRequire

⇒ 错误特征与源码推断逐字一致(number 正是 propTypes 里第一个被求值的字段),栈证明是模块加载期 ✓

★ 这是第四个"早已被移除的 API 导致加载即崩"的库,而且四次的原因各不相同:
React.createClass + ListView、ViewPropTypes、经兼容垫片失效的 ViewPropTypes、以及本次的 React.PropTypes。
四个的
表现完全一致
:require 不抛错、返回 undefined,错误只出现在 LogBox 里。

★★★ 好消息:它的"淡化"行为可以被精确验证

库的行为完全由 Animated.Value 驱动:

constructor(props) {
  this.state = { opacityValue: new Animated.Value(this.props.minOpacity) };   // 初值 0
}
componentWillReceiveProps(nextProps) {
  if (nextProps.message) {
    this.fadeIn();                                        // Animated.timing → maxOpacity
    const timerId = setTimeout(() => {
      this.fadeOut();                                     // Animated.timing → minOpacity
      clearTimeout(timerId);
    }, this.props.timeout);                               // 默认 3000ms
  }
}
fadeIn  = () => { Animated.timing(this.state.opacityValue, {duration: this.props.fadeTime, toValue: this.props.maxOpacity}).start(); }
fadeOut = () => { Animated.timing(this.state.opacityValue, {duration: this.props.fadeTime, toValue: this.props.minOpacity}).start(); }

⇒ 既然透明度本身就是一个 Animated.Value,那就可以给它挂 listener,把整条不透明度曲线读出来(默认配置:fadeTime=500、maxOpacity=0.9、minOpacity=0.0、timeout=3000)。

实测拿到的时间序列(用替代实现跑一遍同样的逻辑):

★ 采样点总数          = 42
★ 不透明度最大值      = 0.9        ← 正好等于 maxOpacity
★ 不透明度最小值      = 0          ← 正好等于 minOpacity
★ 采样明细(最近 24 个)= 0.889,0.86,0.837,0.815,0.786,0.73,0.696,0.657,0.621,0.586,
                          0.541,0.5,0.456,0.409,0.322,0.14,0.119,0.093,0.067,0.027,
                          0.014,0.005,0,0

⇒ 先升到 0.9、再降回 0,一条完整的"淡入 → 保持 → 淡出"曲线 ✓
⇒ 这不是"看起来在闪",而是从 Animated.Value 里直接读出来的数值序列。

★★★ 顺带实证了一条源码级隐患

LogBox 里出现了这条(RN 0.84 报的):

Animated: `useNativeDriver` was not specified. This is a required option and must be specified…

⇒ 库里的 Animated.timing(...) 没有传 useNativeDriver ✓ —— 与源码一致。

★ 还有几处源码级隐患(本轮不触发,仅记录)

const Screen = Dimensions.get('window');        // ← 模块加载时取一次,之后不会再更新
Notification.styles.container = {
  position: 'absolute', bottom: 35,
  width: Screen.width - 80, left: 40, right: 40,
  backgroundColor: '#444', padding: 6, borderRadius: 12, …
};
// 类里【没有 componentWillUnmount】⇒ setTimeout 不会在卸载时清掉
  • Screen 是模块级常量 ⇒ 旋转/分屏后宽度不会更新;
  • 没有 componentWillUnmount ⇒ 组件在 timeout 到期前被卸载,那句 fadeOut() 仍会执行(对已卸载组件调用 setState/Animated 的风险);
  • componentWillReceiveProps 是老生命周期(仅告警)。

几何本身是可算的:宽 = window.width − 80,本机 window.width = 440 ⇒ 360vp;left = 40vp、bottom = 35vp、底色 #444、borderRadius 12。

设备侧断言 17 / 20(其中 A 11/11、B 5/5;C 组 4 条里 3 条在最后一轮因测试脚手架问题未采到样本 —— 详见第六节,同样的 3 条在早先一轮里全部通过并已记录数据)。

在这里插入图片描述


一、先说结论

项结果
上游最新版2.0.0;license: MIT;上游 star ⚠️ 13(13 很低,但仍满足"star > 5")
库类型纯 JS 单文件组件库(index.js 仅 2189 B / 105 行)
是否需要原生适配不需要(无 harmony/、无 NativeModules、无原生代码)—— 但它也用不了
运行时依赖✅ 零依赖(import 图只有 react + react-native)
prepare / postinstall✅ 都没有(只有 precommit)
mainindex.js(源码直发)
需要 HAR / 权限 / ohpm❌ 都不需要
★★★ 致命点从 react import PropTypes ⇒ React 19 上为 undefined ⇒ PropTypes.number(模块作用域)抛 Cannot read property 'number' of undefined ⇒ 加载即崩
★★★ 淡化行为Animated.Value 的 listener 可读出完整曲线:max 0.9、min 0、先升后降(42 个采样)
★★ 告警Animated: useNativeDriver was not specified(RN 0.84 报)
★ 其它隐患无 componentWillUnmount(setTimeout 不清);Dimensions.get 在模块级缓存;componentWillReceiveProps 老生命周期
★ 平台分支 / 兼容垫片✅ 一处都没有(比前几个库干净)

二、判定与接入

步做法结果
①package.json 里有没有 harmony.autolinking没有
②仓库里有没有 harmony/没有
③代码里有没有 NativeModules全无
④import 图体检只有 react + react-native ⇒ 零依赖,不需要补装任何东西 ✓
⑤scripts 扫 prepare 家族✅ 没有
⑥★ 老 API 预扫抓到了:import { PropTypes } from 'react'(从 react 里取 PropTypes)
⑦成员写法预扫(^\s*)两类都有:原型方法 constructor/componentWillReceiveProps/render;箭头类字段 fadeIn/fadeOut
⑧平台分支预扫✅ 无
⑨原生代码痕迹预扫✅ 无
npm install "git+https://atomgit.com/oh-react-native/react-native-notification.git#2.0.0-ohos-1.0.0" --ignore-scripts

⚠️ 装得上,但用不了:

require('react-native-notification')
⇒ TypeError: Cannot read property 'number' of undefined   (在模块加载阶段)

三、致命点的完整证据

页面上直接印出来:

React 版本             = 19.2.3
React.PropTypes        = undefined
React.PropTypes.number = undefined
prop-types(正确来源)  = object        ← 版本 15.8.1

容器化 require(按钮触发、try/catch):

require 成功,typeof = undefined
(LogBox)Uncaught Error / Cannot read property 'number' of undefined
(栈)anonymous → loadModuleImplementation → guardedLoadModule → metroRequire

⇒ 特征词是 number —— 正好是 propTypes 里第一个被求值的字段(timeout: PropTypes.number)✓
⇒ 栈里的 guardedLoadModule 说明是模块求值期 ✓
⇒ 与前三个同类库一样,require 不抛错、返回 undefined ✓


四、淡化行为是怎么验证的

4.1 判据设计

不去"看动画",而是直接读透明度数值:

this.state.opacityValue.addListener(({value}) => {
  samples.push({t: Date.now(), v: Number(value.toFixed(3))});
});

⇒ 一次淡入淡出会产生几十个采样点,构成一条时间序列 ✓

4.2 实测结果

★ 采样点总数     = 42
★ 最大值         = 0.9       ← == maxOpacity(默认 0.9)
★ 最小值         = 0         ← == minOpacity(默认 0.0)
★ 明细(最近 24)= 0.889,0.86,0.837,0.815,0.786,0.73,0.696,0.657,0.621,0.586,0.541,0.5,
                   0.456,0.409,0.322,0.14,0.119,0.093,0.067,0.027,0.014,0.005,0,0

三条判据:

判据结果
有采样(listener 生效)✅
最大值达到 maxOpacity 附近✅ 0.9
序列先升后降(fadeIn → fadeOut)✅
最小值回到 minOpacity 附近✅ 0

⚠️ 明细里 0.322 → 0.14 有一处跳变(采样间隔与动画帧对齐的抖动),不影响"先升后降"的结论 ✓

4.3 几何(可算,但本轮只记录未量像素)

width: Screen.width - 80, left: 40, right: 40, bottom: 35, backgroundColor: '#444'

本机 Dimensions.get('window') 实测 {width: 440, height: 744, scale: 3} ⇒ width = 360vp、left = 40vp、bottom = 35vp ✓

⚠️ 本轮没有量到这条提示的像素坐标:我把替代实现放在了 ScrollView 的内容里,而它是 position: 'absolute' ⇒ 相对内容容器定位 ⇒ 落到了很长的内容底部(dump 里出现在 y≈2224,几乎在屏幕外)。这是我这边的摆放问题(库的设计是放在根 View 里),所以几何只做了源码级推算,没有像素实测 ✓

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


五、替代实现(可直接用)

改动很小:换掉 PropTypes 的来源,其余逻辑照旧:

import React from 'react';
import PropTypes from 'prop-types';            // ★ 换成这个包(不要再从 react 里取)
import {Animated, Dimensions, StyleSheet, Text, View} from 'react-native';

export default class Notification extends React.Component {
  static propTypes = {timeout: PropTypes.number, fadeTime: PropTypes.number,
                      minOpacity: PropTypes.number, maxOpacity: PropTypes.number,
                      message: PropTypes.string};
  static defaultProps = {timeout: 3000, fadeTime: 500, minOpacity: 0, maxOpacity: 0.9, message: ''};

  state = {opacityValue: new Animated.Value(this.props.minOpacity)};

  componentDidUpdate(prev) {
    if (this.props.message && this.props.message !== prev.message) {
      // ★ 补上 useNativeDriver(RN 0.84 会告警要求)
      Animated.timing(this.state.opacityValue,
        {duration: this.props.fadeTime, toValue: this.props.maxOpacity, useNativeDriver: true}).start();
      const id = setTimeout(() => {
        Animated.timing(this.state.opacityValue,
          {duration: this.props.fadeTime, toValue: this.props.minOpacity, useNativeDriver: true}).start();
        clearTimeout(id);
      }, this.props.timeout);
      this._timer = id;                       // ★ 存起来,卸载时清掉(原库没有这一步)
    }
  }

  componentWillUnmount() { clearTimeout(this._timer); }   // ★ 原库缺的就是这一句

  render() {
    if (this.props.message === '') { return null; }       // 与原库一致
    return (
      <Animated.View style={[styles.container, {opacity: this.state.opacityValue}]}>
        <Text style={styles.message}>{this.props.message}</Text>
      </Animated.View>
    );
  }
}

const styles = StyleSheet.create({
  container: {position: 'absolute', bottom: 35, left: 40, right: 40,   // 宽度用 left/right 撑开,避免缓存屏幕宽
              backgroundColor: '#444', alignItems: 'center', padding: 6, borderRadius: 12},
  message: {color: '#fff', fontSize: 12, textAlign: 'center'},
});

改了四处:① prop-types 换成独立包;② 补 useNativeDriver;③ 用 componentDidUpdate 替代老生命周期;④ 补 componentWillUnmount + 用 left/right 撑宽度(不再缓存 Screen.width)。


六、★ 本轮没拿到的一个数字(如实记录)

最后一次重跑时,C 组有 3 条断言失败:

✗ [C] 已有不透明度采样(Animated.Value 的 listener)|期望 true|实际 false
✗ [C] 最大值达到 maxOpacity(0.9) 附近(≥0.85)|期望 true|实际 false
✗ [C] 序列先上升(fadeIn)后下降(fadeOut)|期望 true|实际 false

原因不在库,而在我这一侧,两条叠加:

  1. 我为了清日志重启了应用 ⇒ 采样数据存在内存里,重启即清零;
  2. 重启后我想再触发一次,但定位按钮时按"文字"去查 dump,命中的却是页面上的提示文案:
Text#Paragraph(168) [36,600,1284,639] "(尚无 —— 点「触发一次通知」)"

—— 因为我把提示文案写成了按钮的名字,于是点到了这段文字上(它不可点),没点中按钮 ⇒ 没有新采样 ⇒ C 组必挂 ✓

同一类错误容易反复出现(例如按 placeholder 文字找 TextInput)。规律是:不要用"文字"去 dump 里定位控件 —— 页面上任何地方(标题、提示、说明)都可能包含同样的文字。
更稳的做法是:按控件类型节点(TextInput#TextInput、Button)找,或给要点的东西加一个唯一的标记文本。

⇒ 但这 3 条判据在同一轮的【早先一次运行】里是全部通过的,数据就是第四节里那份(42 个采样、0.9、0、完整序列)✓ ⇒ "淡化行为"本身是已验证的,缺的是"最后一次干净复现" ✓


七、已知限制与本次验证边界

7.1 用这个库要知道的

事项说明
★ 在 RN 0.84 上不可用从 react 里 import PropTypes ⇒ PropTypes.number 在模块作用域抛错 ⇒ 加载即崩
★ 正确来源是 prop-types 包改成 import PropTypes from 'prop-types' 即可
★ Animated.timing 缺 useNativeDriverRN 0.84 会告警要求它
★ 没有 componentWillUnmountsetTimeout 不会在卸载时清掉
★ Screen 是模块级常量Dimensions.get('window') 只在加载时取一次 ⇒ 旋转/分屏后宽度不更新
★ message 为空串时不渲染render() 直接 return null
★ 只有 message 变化才会触发行为完全由 componentWillReceiveProps 驱动,自己不启动
fadeIn / fadeOut 在实例上是箭头类字段(不在 prototype),可用 ref 调

7.2 本次验证的边界

  1. 原库的渲染结果完全未验证(明知加载即崩,故意不触发);
  2. 提示的像素几何未量(我把它放在了 ScrollView 内容里,落到了内容底部;只做了源码级推算 width=360vp / left=40 / bottom=35);
  3. timeout(3s 后自动淡出)的端到端计时未严格验证(采样覆盖了整条曲线,但没有断言"保持段恰好 3s");
  4. useNativeDriver 告警的具体行为未深究(只确认了它会被 RN 报出来);
  5. 卸载时 setTimeout 未清的风险未复现(会触发 red screen 之类,故意不触发);
  6. 旋转/分屏后宽度不更新的问题未实测;
  7. message 从非空变空、从一条换成另一条的情况未逐一验证;
  8. shadow* 阴影未验证;
  9. star 只有 13 ⇒ 上游使用面很窄,社区验证极少;
  10. 只在一台模拟器上验证(Pura X View,density 3,1320×2232),没有真机;未做跨平台对照。

未改动库代码。


八、常见问题

Q1:为什么一装就崩?

因为它是从 react 里取 PropTypes 的:

import React, {Component, PropTypes} from 'react';    // ← PropTypes 早已不在 react 里
const propTypes = {timeout: PropTypes.number, …};     // ← 模块作用域求值 ⇒ 崩

⇒ 实测 React.PropTypes === undefined ⇒ PropTypes.number 抛 Cannot read property 'number' of undefined。

Q2:我 require 它没报错?

它抛了,只是没抛到你手上:Metro 的 guardedLoadModule 会把模块求值期的异常报给 LogBox,而 require 返回 undefined(实测栈:loadModuleImplementation → guardedLoadModule → metroRequire)。⇒ undefined 就是"加载失败"的信号。

Q3:改一行能修好吗?

基本可以 —— 把来源换成独立的包:

import PropTypes from 'prop-types';        // ★ 而不是从 'react' 里取

但建议顺手把另外三处也一起修(见第五节):补 useNativeDriver、补 componentWillUnmount、别缓存 Screen.width。

Q4:怎么知道它的淡入淡出到底对不对?

给它挂 listener 读数值就行:

this.state.opacityValue.addListener(({value}) => console.log(value));

实测会得到一条从 0 升到 0.9 再降回 0 的序列 ✓

Q5:为什么会有 useNativeDriver 的告警?

因为库里的 Animated.timing(state.opacityValue, {duration, toValue}) 没有传 useNativeDriver,RN 0.84 会把它当成必须项来告警。

Q6:message 传空串会怎样?

render() 里 if (this.props.message === '') return null; ⇒ 什么都不渲染 ✓

Q7:这个库需要鸿蒙侧做什么特殊处理吗?

原生侧什么都不需要(纯 JS、零依赖)。障碍全在 JS 侧:一个从 react 里取 PropTypes 的写法。


小结

react-native-notification 是 105 行的纯 JS 轻提示组件(零依赖)。但它在 RN 0.84 上加载即崩。

最值得记下来的是这几条:

  1. ★★★ “从 react 里 import PropTypes” 是第四种加载即崩的写法。
    实测错误特征是 Cannot read property 'number' of undefined(number 正是 propTypes 里第一个被求值的字段),栈在 loadModuleImplementation → guardedLoadModule。
    ⇒ 至此本项目遇到过的四种"已移除 API"分别是:React.createClass + ListView、ViewPropTypes、经兼容垫片失效的 ViewPropTypes、以及本次的 React.PropTypes —— 表现完全一致:require 不抛错、返回 undefined,错误只在 LogBox 里。

  2. ★★★ 透明度驱动的东西,可以直接读数值曲线来验证。
    给它挂一个 Animated.Value 的 listener,就得到 42 个采样点,最大值 0.9(= maxOpacity)、最小值 0(= minOpacity)、先升后降 ✓
    ⇒ 比"看动画"硬得多,也解释了"淡入 → 保持 → 淡出"这一段确实按 fadeTime/timeout 走。

  3. ★★ 顺带被 LogBox 实证的隐患:Animated: useNativeDriver was not specified —— 与源码里 Animated.timing 缺参数完全对应。

  4. ★★ 一处流程教训:不要用"文字"去 dump 里定位控件。
    我为了再触发一次通知,按按钮文字查 dump,结果命中的是页面上的提示文案(我把提示写成了按钮的名字)⇒ 点到不可点的文字上、没触发 ⇒ C 组三条挂掉。
    ⇒ 改用控件类型节点(TextInput#TextInput / Button)定位,或给要点的目标加一个唯一标记 —— 按 placeholder 文字找输入框也会栽在同一件事上。

  5. ★ 一个"零依赖"的库也会崩 —— 本轮的坑跟依赖无关,纯粹是老写法。⇒ 所以"import 图体检"要通过,但它不能替代老 API 预扫。

  6. ★ star 只有 13 —— 数值很低(仍满足"star > 5"的门槛)。上游 2017 年后再无提交,社区验证几乎为零,遇到问题时几乎没有现成答案。


本篇用到的库

项内容
三方库react-native-notification(上游 2.0.0 的鸿蒙适配版)
适配仓库https://atomgit.com/oh-react-native/react-native-notification
适配 TAG2.0.0-ohos-1.0.0
需要 HAR / 权限 / ohpm都不需要(纯 JS、零依赖)
库类型单文件 Toast 式轻提示(在 RN 0.84 上不可用:从 react 里 import PropTypes)
运行时依赖✅ 零
prepare / postinstall✅ 都没有
许可证MIT
上游仓库https://github.com/frostney/react-native-notification(⚠️ ★13)
宿主工程RNOH084Demo(测试页 rnAppKey = NotificationTestApp)
# 从适配仓库安装(零依赖,无需补装)
npm install "git+https://atomgit.com/oh-react-native/react-native-notification.git#2.0.0-ohos-1.0.0" --ignore-scripts

# 本地目录接入
npm install ../react-native-notification --ignore-scripts

⚠️ 装得上、用不了:加载期就会抛 Cannot read property 'number' of undefined。

// ★ 替代实现:四处小改动(见正文第五节)
import React from 'react';
import PropTypes from 'prop-types';                        // ① 换成独立的包
import {Animated, StyleSheet, Text} from 'react-native';

static defaultProps = {timeout: 3000, fadeTime: 500, minOpacity: 0, maxOpacity: 0.9, message: ''};
state = {opacityValue: new Animated.Value(0)};

componentDidUpdate(prev) {                                  // ③ 不用老生命周期
  if (this.props.message && this.props.message !== prev.message) {
    Animated.timing(this.state.opacityValue,
      {duration: 500, toValue: 0.9, useNativeDriver: true}).start();   // ② 补 useNativeDriver
    this._timer = setTimeout(() => Animated.timing(this.state.opacityValue,
      {duration: 500, toValue: 0, useNativeDriver: true}).start(), 3000);
  }
}
componentWillUnmount() { clearTimeout(this._timer); }       // ④ 原库缺这一句

render() {
  if (this.props.message === '') { return null; }           // 与原库一致
  return <Animated.View style={[styles.container, {opacity: this.state.opacityValue}]}>
           <Text style={styles.message}>{this.props.message}</Text>
         </Animated.View>;
}

// 几何:width 用 left/right 撑开,别缓存 Screen.width(原库用 `Dimensions.get` 在模块级取一次)
const styles = StyleSheet.create({
  container: {position: 'absolute', bottom: 35, left: 40, right: 40,
              backgroundColor: '#444', alignItems: 'center', padding: 6, borderRadius: 12},
  message: {color: '#fff', fontSize: 12, textAlign: 'center'},
});

// ⚠️ 原库的问题:`import {PropTypes} from 'react'` ⇒ React 19 上 undefined ⇒ 加载即崩
// ⚠️ Animated.timing 缺 useNativeDriver ⇒ RN 0.84 告警
// ⚠️ 验证淡化:给 Animated.Value 挂 listener 读数值曲线(实测 max 0.9 / min 0 / 先升后降)
# 换页启动测试页 —— force-stop 不能省
hdc shell aa force-stop com.rnoh084.demo
hdc shell aa start -b com.rnoh084.demo -a EntryAbility --ps rnAppKey NotificationTestApp

判据的复现方式

# ① 老 API 预扫(本轮抓到的是"从 react 里取 PropTypes")
#    搜 `from 'react'` 那一行的具名导入里有没有 PropTypes / ViewPropTypes / createClass
# ② 容器化 require(⚠️ 会让 LogBox 整屏红屏,坑 206)⇒ 单独按钮,截图之后再按
devecocli ui layout | Select-String 'logbox_message_contents_text|logbox_stack_frame_text'
#    ⇒ "Cannot read property 'number' of undefined" + 栈里的 guardedLoadModule
# ③ 淡化曲线:给 Animated.Value 挂 listener,把数值打出来
#    ⇒ 期望:升到 maxOpacity(0.9) → 保持 timeout → 降回 minOpacity(0)
# ④ ★ 定位控件不要按"文字"找(页面上别处可能含同样文字)
#    用控件类型节点(TextInput#TextInput / Button),或给目标加唯一标记文本

验证环境

项版本
React Native0.84.1
React19.2.3
RNOH(npm / ohpm)@react-native-oh/react-native-harmony / @rnoh/react-native-openharmony 0.84.3
Node.js / npmv24.14.0 / 11.9.0
DevEco Studio26.0.0.621
HarmonyOS SDKAPI 26(26.0.0.32)
设备HarmonyOS 7.0.0(26.0.0) Beta2 模拟器 Pura X View(ohos-x64),1320×2232,density 3
本机状态栏高度117px = 39vp
宿主依赖✅ 无需补装(库零依赖)
宿主 HAP 产物entry-default-signed.hap
本次构建assembleHap 4 分 03 秒 ⇒ A 11/11 + B 5/5;C 组在早先一轮 4/4,最后一轮因脚手架问题 1/4
验证规模设备侧 A 11 + B 5 = 16 项全通、C 组 4 项中 3 项在早先一轮通过(42 个采样、max 0.9、min 0、先升后降);容器化 require 1 次(LogBox + 调用栈取证);useNativeDriver 告警 1 条;环境事实 4 项;几何源码推算 1 组(360/40/35vp);4 张截图互异

相关社区与项目地址

项目地址
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

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐