刷文档、看视频、导航的时候屏幕自动熄灭,是最扫兴的一件事。expo-keep-awake 就是解决这个的库——让应用在前台时保持屏幕常亮。它是 Expo 体系里的基础库,很多上层库(视频播放器、阅读器、地图导航)都会间接依赖它。

这个库在鸿蒙上没有官方实现,所以我做了一版适配。本文把整条链路写清楚:从上游同步、鸿蒙实现怎么写、到接入宿主并跑通。

环境准备:本文不重复环境搭建步骤。RNOH(React Native for OpenHarmony)开发环境的完整配置见官方开发者指南:
https://atomgit.com/CPF-RN/docs/blob/main/开发者指南/02-搭建准备/环境初始化.md


一、版本配套:四件套必须对齐

RNOH 项目有个硬约束:RN 版本、RNOH 的 npm 包、RNOH 的 ohpm 包、DevEco SDK 四者必须对齐,错一个就是编译报错或者白屏。而且版本矩阵只是通用参考,具体库验证过的组合才算数。

我这次锁定的组合:

项版本
expo-keep-awake57.0.2(与 npm 上游 latest 一致)
React Native0.84.1
React19.2.3
@react-native-oh/react-native-harmony(npm)0.84.3
@rnoh/react-native-openharmony(ohpm)0.84.3
Compile SDK26.0.0
DevEco Studio26.0.0 Release
实现方式TurboModule + CAPI 架构

官方 skill 的版本矩阵里 0.84 系列记的是 RNOH 0.84.2,我这版用的是 0.84.3——以实际验证通过的为准,别照着矩阵硬套。

二、适配步骤

第一步:上游同步到 AtomGit

expo-keep-awake 不是独立仓库,它是 expo/expo monorepo 里的一个包:packages/expo-keep-awake。

我的做法是在 oh-react-native 组织下建一个独立仓库,把上游这个包的源码同步过来,并锁死基线 commit:

upstreamCommit: 9e5319c0f821a27b7924841903abae50e2b41790

锁 commit 这一步不能省。上游是 monorepo,包目录会跟着主仓一起动;不锁基线的话,以后想复现"这版适配对应上游哪份代码"就说不清了。这条信息我写进了仓库的 spec.json。

第二步:本地克隆

git clone https://atomgit.com/oh-react-native/expo-keep-awake.git
cd expo-keep-awake

第三步:确定交付分支与版本号

适配包和普通库不一样,它是要被别的主程按版本引用的,所以版本号必须能一眼看出"上游版本 + 鸿蒙实现版本"。

我用 main 作开发分支,完成后打 TAG 交付:

git tag 57.0.2-ohos-1.0.0

命名规则是 <上游版本>-ohos-<适配版本>。调用方按 TAG 引用,就不会被后续改动影响到:

"expo-keep-awake": "git+https://atomgit.com/oh-react-native/expo-keep-awake.git#57.0.2-ohos-1.0.0"

第四步:适配实现——新增了什么、为什么

这是核心。上游给的是 iOS/Android 实现,鸿蒙侧要从零写。

新增的第一块是 HAR 工程 harmony/keep_awake/:

harmony/keep_awake/
├── Index.ets                                   # 导出 ExpoKeepAwakePackage
├── oh-package.json5                            # 声明包名 @react-native-ohos/expo-keep-awake
├── build-profile.json5
└── src/main/
    ├── module.json5
    ├── cpp/                                    # CAPI 架构下的 C++ 侧
    │   ├── CMakeLists.txt
    │   ├── ExpoKeepAwakePackage.h
    │   └── ExpoKeepAwakePackage.cpp
    └── ets/
        ├── ExpoKeepAwakePackage.ets            # 把 TurboModule 交给 RNOH
        └── ExpoKeepAwakeTurboModule.ts         # ★ 真正的实现

第二块是 TurboModule 的实现。上游在 JS 侧声明了三个方法,我逐个落到鸿蒙:

JS 侧方法鸿蒙实现
isAvailableAsync()探测当前窗口可不可用
activate(tag)把 tag 加入持有集合,设置窗口常亮
deactivate(tag)从集合移除 tag,空了就恢复原标志

核心就一句窗口调用:

await target.setWindowKeepScreenOn(next.size > 0 || original);

target 是当前应用窗口。这里我特意没有去改系统休眠超时,也没有创建后台运行锁——只动自己应用的窗口标志,作用域最小,不需要额外权限,也不会影响全局功耗。上游 Android 实现也是类似的选择。

original 是"接管之前这个窗口的常亮状态"。写成 next.size > 0 || original 而不是直接写 next.size > 0,是为了不擅自关掉宿主本来就设好的常亮。这个细节在第四节展开。

第三块是 package.json 里的 autolinking 声明:

"harmony": {
  "alias": "expo-keep-awake",
  "autolinking": {
    "ohPackageName": "@react-native-ohos/expo-keep-awake",
    "etsPackageClassName": "ExpoKeepAwakePackage",
    "cppPackageClassName": "ExpoKeepAwakePackage",
    "cmakeLibraryTargetName": "rnoh_keep_awake"
  }
}

这四个名字是 RNOH 找到这个包的凭据。少一个或者拼错,表现都是"编译过了但模块没注册",运行时才发现,很难查。

第五步:补全适配仓库所需的额外文件

库的 README 和 CHANGELOG 我没动上游原文,适配相关的东西单独成文件:

文件作用
README.OpenHarmony.md / README.OpenHarmony_CN.md适配说明:能力对照、版本配套、接入方式、已知限制
spec.json机器可读的适配规格:包名、模块名、方法清单、版本配套、基线 commit、验证结论
RN_expo-keep-awake+代码检查报告.md代码检查结论、真机状态与截图索引
harmony/keep_awake.har预编译产物,随包分发,装依赖即可拿到

spec.json 里我记了一份验证数据,方便后来人核对:

"validation": {
  "status": "pass",
  "date": "2026-09-13",
  "systemVersion": "OpenHarmony-7.0.0.105",
  "contractTests": 6,
  "deviceScenarios": 6,
  "screenshots": 6,
  "hapSha256": "043153d1915b1761f228289bb9af851cf82cfdc71daf66baf364f031b1b8f4c9",
  "releaseTag": "57.0.2-ohos-1.0.0"
}

hapSha256 是当时产物的哈希。以后有人怀疑"你验的那版和现在这版是不是同一份",对一下哈希就知道。

第六步:代码推送

git push origin main
git push origin 57.0.2-ohos-1.0.0

三、这个适配包长什么样

克隆下来第一眼会有点意外:它没有 example/,也没有可运行的应用。

expo-keep-awake/
├── package.json          # 含 harmony.autolinking
├── spec.json             # 适配规格
├── src/
│   ├── index.ts          # JS 侧 API
│   └── NativeKeepAwake.ts
├── harmony/
│   ├── keep_awake.har    # 预编译产物(3.2 KB)
│   └── keep_awake/       # HAR 源码
└── README.OpenHarmony*.md

两个要点:

  1. 它是"带原生实现的适配包"。和纯 JS 库不同,它必须编译原生代码,所以不能只 npm install 就完事,还要走 ohpm 和 hvigor。
  2. files 字段里包含 harmony,所以从 git 装依赖时能直接拿到 HAR。
"files": ["src", "harmony", "LICENSE", "README.OpenHarmony.md", "README.OpenHarmony_CN.md"]

四、接入宿主:只有三处改动面

库本身不能独立运行,必须有一个 RNOH 宿主 App。社区已有现成的——oh-react-native/RNOH084Demo 是 RNOH 0.84.3 的多库验证宿主,版本和我这版适配完全一致,而且自带一个很实用的机制:

// harmony/entry/src/main/ets/entryability/EntryAbility.ets
const rnAppKey = want.parameters?.['rnAppKey'] as string | undefined;
AppStorage.setOrCreate('rnAppKey', rnAppKey ?? 'RNOH084Demo');

Index.ets 里 RNApp 的 appKey 取自它,于是一个宿主可以挂很多独立测试页,用命令行参数切换:

hdc shell aa start -b com.rnoh084.demo -a EntryAbility --ps rnAppKey KeepAwakeTestApp

而且它的 bundle 加载链已经是「Metro 优先 + 静态 bundle 兜底」,调代码不用改原生:

new AnyJSBundleProvider([
  new MetroJSBundleProvider(),
  new FileJSBundleProvider('/data/storage/el2/base/files/bundle.harmony.js'),
  new ResourceJSBundleProvider(..., 'hermes_bundle.hbc'),
  new ResourceJSBundleProvider(..., 'bundle.harmony.js')
])

接入要改的地方

第一处:package.json。

"expo-keep-awake": "file:../expo-keep-awake"

也可以按 README 写的方式装:npm install git+https://atomgit.com/oh-react-native/expo-keep-awake.git#57.0.2-ohos-1.0.0,再跑 ./node_modules/.bin/react-native link-harmony。本地 file: 装的好处是不依赖网络,改完直接生效。

第二处:两级 oh-package.json5 都要写 HAR。

"@react-native-ohos/expo-keep-awake":
  "file:../node_modules/expo-keep-awake/harmony/keep_awake.har",

harmony/oh-package.json5 管工程级、harmony/entry/oh-package.json5 管模块级,两处都要加。只加一处会出现"能找到包但链接不上"。

第三处:在 ETS 侧注册 Package。

// harmony/entry/src/main/ets/RNOHPackagesFactory.ets
import type { RNPackageContext, RNOHPackage } from '@rnoh/react-native-openharmony';
import ExpoKeepAwakePackage from '@react-native-ohos/expo-keep-awake';

export function createRNOHPackages(ctx: RNPackageContext): RNOHPackage[] {
  return [
    new ExpoKeepAwakePackage(ctx),
  ];
}

代码写在哪,这里说清楚:接入的全部改动面就是这三个文件。C++ 侧不用手改——CAPI 架构下 PackageProvider.cpp 会自动消费 autolinking 生成的 RNOHPackagesFactory.h。

五、实现上的三个设计点

点一:用 tag 集合管理持有者

上游的语义是"按标签持有":多个业务方各自持有一个 tag,谁都不释放就一直常亮。我用 Set<string> 记当前持有者:

private tags: Set<string> = new Set<string>();

private change(tag: string, activate: boolean): Promise<void> {
  if (!activate && !this.tags.has(tag)) return;   // ← 释放未知 tag 直接返回
  const next = new Set<string>(this.tags);
  if (activate) next.add(tag);
  else next.delete(tag);
  await target.setWindowKeepScreenOn(next.size > 0 || original);
  this.tags = next;                                // ← 设置成功后才提交
}

两个细节值得说:

  • 先复制再改、成功后才提交:next 是新集合,只有 setWindowKeepScreenOn 成功返回后才 this.tags = next。原生设置失败时,持有者集合不会被改坏,调用方可以重试。
  • 释放未知 tag 是 no-op:if (!activate && !this.tags.has(tag)) return;。某个业务方重复释放、或者释放自己从没申请过的 tag,都不会误伤别人持有的常亮。这一点我专门测了。

点二:恢复"接管前的原值",而不是硬置假

await target.setWindowKeepScreenOn(next.size > 0 || original);

original 是接管之前窗口的常亮状态。只要有任意一个 tag 还持有就保持常亮;全部释放了,恢复成原来的值,而不是硬置为 false。 如果宿主本来就设了常亮,我不会擅自关掉它。

模块销毁时同样恢复:

await this.boundWindow.setWindowKeepScreenOn(this.originalKeepOn);
this.tags.clear();

窗口已经销毁时只记一条警告,不抛错:

hilog.warn(0x0000, 'ExpoKeepAwake', 'Window unavailable during wake-lock cleanup');

点三:addListener 保持"不可用"

export function addListener(...): EventSubscription {
  const error = Object.assign(new Error('ExpoKeepAwake.addListenerForTag is unavailable on harmony'), {
    name: 'UnavailabilityError', code: 'ERR_UNAVAILABLE',
  });
  throw error;
}

上游的 addListener 监听的是浏览器 wake-lock 的释放事件,原生平台本来就没有。我没有假装支持,而是和 iOS/Android 一样抛 ERR_UNAVAILABLE。

这一点很关键:调用方按平台写降级逻辑时,行为要一致。如果鸿蒙返回一个"永不回调的订阅",对方会以为监听成功了,问题要到很久以后才暴露。

六、构建与运行

# 1) 装 JS 依赖
npm install

# 2) 生成调试签名 + 装 ohpm 依赖
cd harmony
devecocli signature generate
ohpm install --all

# 3) 打包 JS bundle(输出到 harmony/entry/src/main/resources/rawfile/)
cd ..
npm run dev

# 4) 编译 HAP
cd harmony
hvigorw --mode module -p product=default -p module=entry@default assembleHap --no-daemon

# 5) 安装 + 启动测试页
hdc install -r entry/build/default/outputs/default/entry-default-signed.hap
hdc shell aa start -b com.rnoh084.demo -a EntryAbility --ps rnAppKey KeepAwakeTestApp

耗时要有心理准备:首次原生编译 37 分 50 秒,其中 BuildNativeWithNinja 一项就 37 分 6 秒。RNOH 的 C++ 体量大,而且我为模拟器放开了两个 ABI(arm64-v8a + x86_64)。增量构建快得多。

还有个容易误判的地方:hvigor 打完 CompileArkTS 那一行之后就不再逐行输出了,原生阶段可能几十分钟没有新日志。别以为卡死了——去看进程,clang++ 还在跑就是正常的。

七、踩坑记录

坑一:宿主的 package-lock.json 会拦住你

裁剪完宿主依赖后直接 npm install:

npm error code EMISSINGTARGET
npm error Missing target in lock file: "../../private/tmp/lib_react-native-annotated-text"

锁文件里还记着已删掉的依赖。删 package-lock.json 和 node_modules 重装即可。

坑二:metro.config.js 指向不存在的目录

Error "ENOENT" reading contents of "...\react-native-image-pixelmap", skipping.
Failed to construct transformer: ENOENT: no such file or directory, stat
  '...\react-native-document-scanner-plugin'

watchFolders 只留真正存在的那个:

watchFolders: [path.resolve(__dirname, '../expo-keep-awake')],

顺带一个知识点:本地 file: 依赖在 node_modules 里是 symlink,不把库的真实目录加进 watchFolders,metro 解析不到它的源码。

坑三:babel.config.js 里挂着已删依赖的插件

error index.js: Cannot find module 'react-native-worklets/plugin'

宿主原来给 reanimated 系库挂了 worklets 插件,依赖裁掉了,插件也得删。

坑四:compatibleSdkVersion 太低会构建期被拦

00306004 Specification Limit Violation
Error Message: The project's compatibleSdkVersion: 12 cannot be lower than
the minimum compatible version 17 required by the dependencies:
@react-native-ohos/expo-keep-awake.

宿主原来是 5.0.0(12),而 HAR 声明的最低兼容版本是 API 17。抬到 5.1.0(18) 即可。

这个报错本身是好事:说明 HAR 的 module.json5 里声明了自己的最低兼容版本,依赖方过低会在构建期被直接拦下,而不是等到运行时才炸。做适配包时应该在 module.json5 里如实声明这个版本。

坑五:模拟器是 x64,默认只编 arm64

宿主 build-profile.json5 里没有 abiFilters,默认只出 arm64-v8a,装到 ohos-x64 模拟器上直接失败。要显式放开:

"buildOption": {
  "externalNativeOptions": {
    "path": "./src/main/cpp/CMakeLists.txt",
    "abiFilters": ["arm64-v8a", "x86_64"]
  }
}

代价是编译量翻倍——这也是首次构建 38 分钟的原因之一。只上真机的话可以去掉 x86_64。

坑六:DEVECO_HOME 指向了错的 DevEco

这台机器上装了两个 DevEco Studio:C:\Program Files\Huawei\DevEco Studio(6.1.1.280)和 E:\dev\DevEco Studio(26.0.0.621)。环境检测脚本按"默认安装路径"探测,一开始取的是 C 盘那个,还把 SDK 连带读成 6.1.1.125 / API 24。把 DEVECO_HOME 指向 E 盘后立刻变成 26.0.0.621 + SDK 26.0.0.32 / API 26。

脚本报的版本不一定是你以为的那个安装,配完环境要回读一次确认。

八、真机验证

验证环境:Pura X View 模拟器,HarmonyOS 7.0.0(26.0.0) Beta2,API 26,ohos-x64。

我写了一个自检台测试页,覆盖五个能力:可用性探测、按 tag 激活/释放、Hook 挂载释放、addListener 边界、事件记录列表。

可用性与按 tag 操作:

[keep-awake-test] isAvailableAsync() -> true
[keep-awake-test] activateKeepAwakeAsync('reading') -> ok
[keep-awake-test] activateKeepAwakeAsync('reading') -> ok     ← 重复激活,幂等
[keep-awake-test] activateKeepAwakeAsync('video') -> ok
[keep-awake-test] deactivateKeepAwake('reading') -> ok        ← 此时 video 仍持有
[keep-awake-test] deactivateKeepAwake('video') -> ok

在这里插入图片描述
在这里插入图片描述

Hook 的挂载与释放:

[keep-awake-test] HookHolder mounted -> useKeepAwake('hook-tag')
[keep-awake-test] HookHolder unmounted -> release('hook-tag')

在这里插入图片描述

addListener 边界:

[keep-awake-test] addListener() -> UnavailabilityError / ERR_UNAVAILABLE(符合预期:鸿蒙不支持 Web wake-lock 事件)

在这里插入图片描述

原生侧确认 TurboModule 真的注册了:

RNInstance::TurboModuleProvider  TM created: ExpoKeepAwake
TurboModuleFactory.cpp:54> Creating Turbo Module: ExpoKeepAwake
RNOH084Demo --> onCreate rnAppKey=KeepAwakeTestApp

能力对照

能力结果
isAvailableAsync()✅ 返回 true
activateKeepAwakeAsync(tag)✅ 按 tag 持有;相同 tag 重复激活幂等
deactivateKeepAwake(tag)✅ 释放对应 tag;未知 tag 为 no-op
useKeepAwake(tag)✅ 挂载激活、卸载释放
addListener(...)✅ 抛 UnavailabilityError / ERR_UNAVAILABLE

九、已知限制

一、常亮只作用于当前窗口。 应用退到后台、窗口销毁、或者系统电源策略介入时,仍由系统说了算。这个库解决的是"前台不被息屏",不是"设备不睡"。

二、不修改系统休眠超时,也不创建后台运行锁。 这是刻意的选择——改系统设置需要更高权限,创建后台锁影响全局功耗。只用应用自己的窗口标志,作用域最小、不需要额外权限。

三、窗口常亮标志本身没有系统侧读数。 验证做到了三条证据:① JS 侧每个 API 的返回值;② 原生 hilog 里的 TM created: ExpoKeepAwake(证明走的是真实实现,不是空壳);③ 源码里确实调用 setWindowKeepScreenOn。但想读窗口的 keepScreenOn 位时被挡住了:

hdc shell hidumper -s WindowManagerService -a '-a'   → 输出 0 字节

hdc shell 的身份是 uid=2000(shell),对这个系统服务没有 dump 权限。所以我把这一条也留在 spec.json 的 limits 里,不当成已验证。

四、物理息屏时序未测。 有全局屏幕超时覆盖生效时,没法可靠地验证"该睡的时候会不会睡"。这条同样是 spec.json 里如实记录的限制。

五、其他 ROM / 设备未验证。 适配方记录的是 OpenHarmony-7.0.0.105;本次在 HarmonyOS 7.0.0(26.0.0) Beta2 模拟器上通过。不同厂商 ROM 的窗口策略可能不同。

六、多个库同时改同一窗口标志时需要业务协调。 我会恢复"接管前"的原值,但如果另一个库也在改同一个标志,最终状态取决于调用顺序。

十、常见问题

Q:为什么不能直接 npm install expo-keep-awake?
A:npm 上那个包只有 iOS/Android 实现,没有鸿蒙原生代码。本仓库是独立的鸿蒙实现,要按 git+...#57.0.2-ohos-1.0.0 或者本地 file: 的方式装。README 里也写明了这一点。

Q:装了之后要不要额外依赖 expo-modules-core?
A:不需要。这版是按 RNOH 的 TurboModule + autolinking 规范实现的,package.json 里的 harmony 字段就是它接入 RNOH 的全部凭据,不依赖 Expo 的模块框架。

Q:activateKeepAwake 和 activateKeepAwakeAsync 用哪个?
A:用异步版。同步版是上游的弃用接口,调用时会打 console.warn,内部还是转发到异步实现。保留它只是为了兼容老代码。

Q:重复激活同一个 tag 会不会报错?
A:不会,是幂等的。Set 语义天然去重,验证时连续调用两次 activateKeepAwakeAsync('reading') 都返回 ok。

Q:释放一个我从没申请过的 tag 会怎样?
A:什么都不做。实现里有 if (!activate && !this.tags.has(tag)) return;,避免误伤其他业务方持有的常亮。这和其他平台的语义一致,也专门验证过。

Q:在鸿蒙上 addListener 为什么直接抛异常?
A:因为它监听的是浏览器 wake-lock 释放事件,原生平台没有这个概念。我的选择是和 iOS/Android 保持一致地抛 ERR_UNAVAILABLE,而不是静默返回一个永不回调的订阅——后者会让调用方以为监听成功了。代码里用到它的话要按平台降级。

Q:为什么我在模拟器上编译要 38 分钟?
A:RNOH 的 C++ 原生库体量大,而且为了跑 ohos-x64 模拟器放开了两个 ABI,编译量翻倍。只上真机的话去掉 x86_64 会明显缩短;同工程二次构建是增量的,也快得多。

Q:怎么确认库真的生效了,而不是只是没报错?
A:三条证据一起看:① JS 侧每个 API 的返回值;② 原生 hilog 里的 TM created: ExpoKeepAwake(证明 TurboModule 注册成功,不是走了空实现);③ 读源码确认调用了 setWindowKeepScreenOn。想看第四层证据(窗口标志位)得在真机上观察息屏行为——这条我还没做到,见"已知限制"。

Q:宿主里为什么会有 rnAppKey 这种东西?
A:那是 RNOH084Demo 宿主自带的机制——一个宿主挂多个库的独立测试页,用命令行参数切换,互不干扰。--ps rnAppKey KeepAwakeTestApp 就是启动本库的测试页。做多库验证时非常省事。

小结

这个库本身很小——核心实现不到 60 行,API 只有五个。但适配过程把 RNOH 接入的完整链路过了一遍:

  • autolinking 的四个身份名(ohpm 包名、ETS 包类、C++ 包类、CMake 目标),少一个都是"编译过了但模块没注册";
  • HAR 的工程级与模块级双重声明,缺一处就链接不上;
  • 版本四件套必须对齐,且以实测组合为准;
  • HAR 里的 compatibleSdkVersion 有约束力,依赖方版本过低会在构建期被拦下。

几个我认为最值得记的设计选择:

  • next.size > 0 || original 是这版实现的核心一行——恢复"接管前的状态"而不是硬置假,宿主本来就常亮时不会被擅自关掉;
  • addListener 选择抛异常而不是静默——宁可让调用方明确知道"这个平台不支持",也不给一个假的订阅;
  • 只在窗口层面做常亮,不碰系统休眠超时、不建后台锁,把作用域压到最小。

适配本身之外,这次也更清楚地看到:RN 库的"能跑起来"和"能装进宿主"是两件事。库自己只有 src/ + harmony/,没有 example/;真正跑起来靠的是宿主。而社区那个 RNOH084Demo 宿主——自带 rnAppKey 多测试页切换——把这一步的成本压得很低。


本篇用到的库

项内容
三方库expo-keep-awake(上游 57.0.2 的鸿蒙适配版)
适配仓库https://atomgit.com/oh-react-native/expo-keep-awake
适配 TAG57.0.2-ohos-1.0.0
ohpm 包名@react-native-ohos/expo-keep-awake
HARharmony/keep_awake.har
基线 commit9e5319c0f821a27b7924841903abae50e2b41790
宿主工程RNOH084Demo(测试页 rnAppKey = KeepAwakeTestApp)
"expo-keep-awake": "git+https://atomgit.com/oh-react-native/expo-keep-awake.git#57.0.2-ohos-1.0.0"
// harmony/oh-package.json5 与 harmony/entry/oh-package.json5 都要加
"@react-native-ohos/expo-keep-awake":
  "file:../node_modules/expo-keep-awake/harmony/keep_awake.har",

验证环境

项版本
React Native0.84.1
React19.2.3
RNOH(npm / ohpm)@react-native-oh/react-native-harmony / @rnoh/react-native-openharmony 0.84.3
Node.jsv24.14.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)
宿主 HAP 产物entry-default-signed.hap(75.4 MB)

欢迎加入 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

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

更多推荐