From ec02338661ef2adbd9c61c56757782321787a5c6 Mon Sep 17 00:00:00 2001
From: dingchenjie
Date: Sat, 12 Sep 2026 15:38:56 +0800
Subject: [PATCH] Adapt to the RN0.84 framework and upgrade the baseline to
4.2.1, version: 4.0.0-beta.1
Signed-off-by: dingchenjie
---
CHANGELOG.md | 5 +
COMMITTERS.md | 7 +
OAT.xml | 75 +
.../README.OpenSource => README.OpenSource | 6 +-
README.md | 403 +-
README_en.md | 398 ++
harmony/reactNativeCamera.har | Bin 47753 -> 50413 bytes
harmony/reactNativeCamera/index.ets | 32 +-
harmony/reactNativeCamera/oh-package.json5 | 4 +-
.../src/main/cpp/ComponentDescriptors.h | 32 +-
.../src/main/cpp/EventEmitters.cpp | 32 +-
.../src/main/cpp/EventEmitters.h | 32 +-
.../src/main/cpp/FaceNativeTurboModule.cpp | 32 +-
.../src/main/cpp/FaceNativeTurboModule.h | 32 +-
.../cpp/NativeCameraComponentDescriptor.h | 32 +-
.../cpp/NativeCameraEventEmitRequestHandler.h | 32 +-
.../src/main/cpp/NativeCameraJSIBinder.h | 34 +-
.../src/main/cpp/NativeCameraPackage.h | 32 +-
.../reactNativeCamera/src/main/cpp/Props.cpp | 34 +-
.../reactNativeCamera/src/main/cpp/Props.h | 34 +-
.../src/main/cpp/RNCCameraModule.cpp | 4 +
.../src/main/cpp/ShadowNodes.cpp | 32 +-
.../src/main/cpp/ShadowNodes.h | 32 +-
.../reactNativeCamera/src/main/cpp/States.cpp | 32 +-
.../reactNativeCamera/src/main/cpp/States.h | 32 +-
.../src/main/ets/FaceDectorPackage.ets | 32 +-
.../src/main/ets/FaceDectorTurboModule.ts | 32 +-
.../reactNativeCamera/src/main/ets/Logger.ts | 32 +-
.../src/main/ets/ReactCameraView.ets | 110 +-
.../src/main/ets/ReactNativeCameraPackage.ets | 54 +-
.../main/ets/ReactNativeCameraTurboModule.ts | 162 +-
.../src/main/ets/core/CameraConfig.ts | 18 +-
.../src/main/ets/core/CameraDeviceInfo.ts | 22 +-
.../src/main/ets/core/CameraEnumBox.ts | 21 +-
.../src/main/ets/service/CameraManager.ts | 16 +-
.../src/main/ets/service/CameraSession.ts | 105 +-
.../src/main/ets/service/ScanSession.ts | 16 +-
.../src/main/ets/types/AuthType.ts | 32 +-
.../src/main/ets/types/CameraError.ts | 16 +-
.../main/ets/types/ReactNativeCameraProps.ets | 34 +-
.../src/main/ets/types/TempCameraProp.ts | 34 +-
.../src/main/ets/types/TemporaryFile.ts | 16 +-
.../src/main/ets/types/VideoFile.ts | 16 +-
.../main/ets/types/VisionCameraModuleSpec.ts | 16 +-
.../main/ets/types/VisionCameraViewSpec.ts | 16 +-
.../src/main/ets/utils/Logger.ts | 16 +-
.../src/main/ets/utils/OrientationUtils.ets | 32 +-
.../src/main/ets/utils/PermissionUtils.ts | 16 +-
.../src/main/ets/utils/Utils.ts | 16 +-
harmony/reactNativeCamera/ts.ets | 32 +-
jest.config.js | 15 +
jest/__tests__/constants-defaultprops-test.js | 104 +
jest/__tests__/events-test.js | 91 +
jest/__tests__/facedetector-test.js | 34 +
jest/__tests__/index-test.js | 60 +
jest/__tests__/platform-routing-test.js | 108 +
jest/babel.config.js | 26 +
jest/coverage/clover.xml | 280 ++
jest/coverage/coverage-final.json | 4 +
.../coverage/lcov-report/FaceDetector.js.html | 265 ++
jest/coverage/lcov-report/RNCamera.js.html | 3262 +++++++++++++++++
jest/coverage/lcov-report/base.css | 224 ++
jest/coverage/lcov-report/block-navigation.js | 87 +
jest/coverage/lcov-report/favicon.png | Bin 0 -> 445 bytes
jest/coverage/lcov-report/index.html | 146 +
jest/coverage/lcov-report/index.js.html | 103 +
jest/coverage/lcov-report/prettify.css | 1 +
jest/coverage/lcov-report/prettify.js | 2 +
.../lcov-report/sort-arrow-sprite.png | Bin 0 -> 138 bytes
jest/coverage/lcov-report/sorter.js | 210 ++
jest/coverage/lcov.info | 605 +++
jest/helpers/nativeCameraMock.js | 36 +
jest/helpers/nativeCameraModuleMock.js | 31 +
jest/helpers/nativeFaceDetectorMock.js | 18 +
jest/helpers/propTypesMock.js | 46 +
jest/helpers/reactMock.js | 47 +
jest/helpers/reactNativeMock.js | 77 +
jest/jest.config.js | 94 +
jest/jest.setup.js | 22 +
package.json | 18 +-
src/NativeCamera.ts | 2 +
src/NativeCameraModule.ts | 4 +
src/RNCamera.js | 92 +-
src/index.js | 4 +-
types/index.d.ts | 26 +-
85 files changed, 7861 insertions(+), 615 deletions(-)
create mode 100644 COMMITTERS.md
create mode 100644 OAT.xml
rename harmony/reactNativeCamera/README.OpenSource => README.OpenSource (72%)
create mode 100644 README_en.md
create mode 100644 jest.config.js
create mode 100644 jest/__tests__/constants-defaultprops-test.js
create mode 100644 jest/__tests__/events-test.js
create mode 100644 jest/__tests__/facedetector-test.js
create mode 100644 jest/__tests__/index-test.js
create mode 100644 jest/__tests__/platform-routing-test.js
create mode 100644 jest/babel.config.js
create mode 100644 jest/coverage/clover.xml
create mode 100644 jest/coverage/coverage-final.json
create mode 100644 jest/coverage/lcov-report/FaceDetector.js.html
create mode 100644 jest/coverage/lcov-report/RNCamera.js.html
create mode 100644 jest/coverage/lcov-report/base.css
create mode 100644 jest/coverage/lcov-report/block-navigation.js
create mode 100644 jest/coverage/lcov-report/favicon.png
create mode 100644 jest/coverage/lcov-report/index.html
create mode 100644 jest/coverage/lcov-report/index.js.html
create mode 100644 jest/coverage/lcov-report/prettify.css
create mode 100644 jest/coverage/lcov-report/prettify.js
create mode 100644 jest/coverage/lcov-report/sort-arrow-sprite.png
create mode 100644 jest/coverage/lcov-report/sorter.js
create mode 100644 jest/coverage/lcov.info
create mode 100644 jest/helpers/nativeCameraMock.js
create mode 100644 jest/helpers/nativeCameraModuleMock.js
create mode 100644 jest/helpers/nativeFaceDetectorMock.js
create mode 100644 jest/helpers/propTypesMock.js
create mode 100644 jest/helpers/reactMock.js
create mode 100644 jest/helpers/reactNativeMock.js
create mode 100644 jest/jest.config.js
create mode 100644 jest/jest.setup.js
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b2f8c00cf..d667ec7be 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,9 @@
[**THE CHANGELOG OF FURTHER VERSIONS (STARTING WITH 1.4.0) IS MAINTAINED WITH GITHUB RELEASES AND CAN BE FOUND HERE**](https://github.com/react-native-community/react-native-camera/releases)
+
+#### 4.0.0-beta.1
+
+* Adapt to the RN0.84 framework and upgrade the baseline to 4.2.1
+
#### 3.42.0
* release version 3.42.0
diff --git a/COMMITTERS.md b/COMMITTERS.md
new file mode 100644
index 000000000..c2ee75d65
--- /dev/null
+++ b/COMMITTERS.md
@@ -0,0 +1,7 @@
+## Committers列表
+
+### 以下是此项目的committer人员
+
+不区分先后顺序
+
+- [xiafeng_xf_admin](https://gitee.com/xiafeng_xf_admin)
\ No newline at end of file
diff --git a/OAT.xml b/OAT.xml
new file mode 100644
index 000000000..3b9f3f8a0
--- /dev/null
+++ b/OAT.xml
@@ -0,0 +1,75 @@
+
+
+
+ LICENSE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/harmony/reactNativeCamera/README.OpenSource b/README.OpenSource
similarity index 72%
rename from harmony/reactNativeCamera/README.OpenSource
rename to README.OpenSource
index c87a179b4..a1ef097c5 100644
--- a/harmony/reactNativeCamera/README.OpenSource
+++ b/README.OpenSource
@@ -2,9 +2,9 @@
{
"Name": "react-native-camera",
"License": "MIT License",
- "License File": "https://github.com/react-native-camera/react-native-camera/blob/v3.40.0/LICENSE",
- "Version Number": "3.40.0",
- "Owner" : "react-native-camera"
+ "License File": "https://github.com/react-native-camera/react-native-camera/blob/v4.2.1/LICENSE",
+ "Version Number": "v4.2.1",
+ "Owner" : "ding_chengjie@hoperun.com",
"Upstream URL": "https://github.com/react-native-camera/react-native-camera",
"Description": "A Camera component for React Native. Also supports barcode scanning!"
}
diff --git a/README.md b/README.md
index d09eeb1c3..4636a80c1 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,402 @@
-# @react-native-ohos/react-native-camera
+> 模板版本:v0.4.2
-This project is based on [react-native-camera](https://github.com/react-native-camera/react-native-camera)
+
+
react-native-camera
+
-## Documentation
+本项目基于 [react-native-camera](https://github.com/react-native-camera/react-native-camera/tree/v4.2.1) 开发。
-- [中文 ](https://gitcode.com/CPF-RN/usage-docs/blob/master/zh-cn/react-native-camera.md)
+请到三方库的 Releases 发布地址查看配套的版本信息:[@react-native-ohos/react-native-camera Releases](https://github.com/react-native-oh-library/react-native-camera/releases)。对于未发布到npm的旧版本,请参考[安装指南](./tgz-usage.md)安装tgz包。
-- [英文 ](https://gitcode.com/CPF-RN/usage-docs/blob/master/en/react-native-camera.md)
+| 三方库名称 | 三方库版本(npm地址) | 发布信息 | 支持RN版本 | Autolink | 编译API版本 | 社区基线版本 | 源码地址 |
+| - | - | - | - | - | - | - | - |
+| @react-native-ohos/react-native-camera | [~4.0.0 (开发中)](https://www.npmjs.com/package/@react-native-ohos/react-native-camera) | [Releases](https://github.com/react-native-oh-library/react-native-camera/releases) | 0.84.* | 是 | API12+ | v4.2.1 | [sig](https://github.com/react-native-oh-library/react-native-camera/tree/sig) |
+| @react-native-ohos/react-native-camera | [~3.42.0](https://www.npmjs.com/package/@react-native-ohos/react-native-camera) | [Releases](https://github.com/react-native-oh-library/react-native-camera/releases) | 0.82.* | 是 | API12+ | v3.40.0 | [br_rnoh0.82](https://github.com/react-native-oh-library/react-native-camera/tree/br_rnoh0.82) |
+| @react-native-ohos/react-native-camera | [~3.41.1](https://www.npmjs.com/package/@react-native-ohos/react-native-camera) | [Releases](https://github.com/react-native-oh-library/react-native-camera/releases) | 0.77.* | 否 | API12+ | v3.40.0 | [br_rnoh0.77](https://github.com/react-native-oh-library/react-native-camera/tree/br_rnoh0.77) |
+| @react-native-ohos/react-native-camera | [~3.40.1](https://www.npmjs.com/package/@react-native-ohos/react-native-camera) | [Releases](https://github.com/react-native-oh-library/react-native-camera/releases) | 0.72.* | 否 | API12+ | v3.40.0 | [br_rnoh0.72](https://github.com/react-native-oh-library/react-native-camera/tree/br_rnoh0.72) |
-## License
+## 简介
-This library is licensed under [The MIT License (MIT)](https://github.com/react-native-camera/react-native-camera/blob/master/LICENSE)
+react-native-camera 是 React Native 的相机组件,同时支持条码扫描。
+本仓库为 `@react-native-ohos/react-native-camera`,当前版本(4.0.0-beta.1)已适配 RN 0.84 框架,并将社区基线升级至 react-native-camera v4.2.1:JS 层采用 codegen spec(NativeCamera / NativeCameraModule / NativeFaceDetector)接入,鸿蒙侧基于 Camera Kit / AVRecorder 实现预览、拍照、录像与扫码能力。
+
+## 下载安装
+
+进入到工程目录并输入以下命令:
+
+**npm**
+
+```bash
+npm install @react-native-ohos/react-native-camera
+```
+
+**yarn**
+
+```bash
+yarn add @react-native-ohos/react-native-camera
+```
+
+## Link
+
+| | 是否支持autolink | RN框架版本 |
+| - | - | - |
+| ~4.0.0 | 是 | 0.84 |
+
+使用AutoLink的工程需要根据该文档配置,Autolink框架指导文档:https://gitcode.com/openharmony-sig/ohos_react_native/blob/master/docs/zh-cn/Autolinking.md
+
+如您使用的版本支持 Autolink,并且工程已接入 Autolink,可跳过ManualLink配置。
+
+ ManualLink: 此步骤为手动配置原生依赖项的指导
+
+首先需要使用 DevEco Studio 打开项目里的 HarmonyOS 工程 `harmony`。
+
+### 1. Overrides RN SDK
+
+为了让工程依赖同一个版本的 RN SDK,需要在工程根目录的 `oh-package.json5` 添加 overrides 字段,指向工程需要使用的 RN SDK 版本。替换的版本既可以是一个具体的版本号,也可以是一个模糊版本,还可以是本地存在的 HAR 包或源码目录。
+
+```json
+{
+ "overrides": {
+ "@rnoh/react-native-openharmony": "file:./react_native_openharmony.har"
+ }
+}
+```
+
+### 2. 引入原生端代码
+
+方法一:通过 har 包引入(推荐)
+
+> [!TIP] har 包位于三方库安装路径的 `harmony` 文件夹下。
+
+打开 `entry/oh-package.json5`,添加以下依赖
+
+```json
+"dependencies": {
+ "@react-native-ohos/react-native-camera": "file:../../node_modules/@react-native-ohos/react-native-camera/harmony/reactNativeCamera.har"
+ }
+```
+
+点击右上角的 `sync` 按钮
+
+或者在命令行终端执行:
+
+```bash
+cd entry
+ohpm install
+```
+
+方法二:直接链接源码
+
+> [!TIP] 如需使用直接链接源码,请参考[直接链接源码说明](https://gitcode.com/CPF-RN/usage-docs/blob/master/zh-cn/link-source-code.md)
+
+### 3. 配置 CMakeLists 和引入 NativeCameraPackage
+
+打开 `entry/src/main/cpp/CMakeLists.txt`,添加:
+
+```diff
++ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
+
+# RNOH_BEGIN: manual_package_linking_1
++ add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-camera/src/main/cpp" ./reactNativeCamera)
+# RNOH_END: manual_package_linking_1
+
+# RNOH_BEGIN: manual_package_linking_2
++ target_link_libraries(rnoh_app PUBLIC rnoh_native_camera)
+# RNOH_END: manual_package_linking_2
+```
+
+打开 `entry/src/main/cpp/PackageProvider.cpp`,添加:
+
+```diff
+#include "RNOH/PackageProvider.h"
++ #include "NativeCameraPackage.h"
+
+using namespace rnoh;
+
+std::vector> PackageProvider::getPackages(Package::Context ctx) {
+ return {
++ std::make_shared(ctx)
+ };
+}
+```
+
+### 4. 在 ArkTS 侧引入 ReactNativeCameraPackage
+
+打开 `entry/src/main/ets/RNPackagesFactory.ts`,添加:
+
+```diff
+ ...
++ import ReactNativeCameraPackage from '@react-native-ohos/react-native-camera';
+
+export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
+ return [
++ new ReactNativeCameraPackage(ctx)
+ ];
+}
+```
+
+> [!TIP] 本库的 ArkTS 组件(ReactCameraView)由 `ReactNativeCameraPackage` 内部的组件 builder 注册(`createWrappedCustomRNComponentBuilderByComponentNameMap`)自动提供,宿主无需在 `buildCustomRNComponent` 或 `arkTsComponentNames` 中额外配置。
+
+
+### 运行
+
+点击右上角的 `sync` 按钮
+
+或者在命令行终端执行:
+
+```bash
+cd entry
+ohpm install
+```
+
+然后编译、运行即可。
+
+## 约束与限制
+
+### 兼容性
+
+要使用此库,需要使用正确的 React-Native 和 RNOH 版本。另外,还需要使用配套的 DevEco Studio 和 手机 ROM。
+
+在以下版本验证通过:
+
+1. RNOH: 0.84.2; SDK: HarmonyOS 6.0.1 Release SDK; IDE: DevEco Studio 6.0.1 Release; ROM: 6.0.0.120 SP7;
+
+### 编译运行API要求
+
+> [!TIP] 当前三方库所有版本均已实现版本隔离,支持在 `API12+` 工程编译,及 `API12+` ROM运行。
+
+> [!TIP] 以下功能依赖特定版本的API,使用 `低于指定API版本的工程编译` 或 `低于指定API版本的ROM运行` 均可能导致部分功能受限。
+1. `whiteBalance` 属性需要在支持 `API20+` 的工程编译,并在支持 `API20+` 的 ROM 上运行,方可生效。
+
+### 权限要求
+
+#### 在 entry 目录下的 module.json5 中添加权限
+
+打开 `entry/src/main/module.json5`,添加:
+
+```diff
+...
+"requestPermissions": [
++ {
++ "name": "ohos.permission.CAMERA",
++ "reason": "$string:camera_reason",
++ "usedScene": {
++ "abilities": [
++ "EntryAbility"
++ ],
++ "when":"inuse"
++ }
++ },
++ {
++ "name": "ohos.permission.MICROPHONE",
++ "reason": "$string:microphone_reason",
++ "usedScene": {
++ "abilities": [
++ "EntryAbility"
++ ],
++ "when":"inuse"
++ }
++ },
+]
+```
+
+#### 在 entry 目录下添加申请以上权限的原因
+
+打开 `entry/src/main/resources/base/element/string.json`,添加:
+
+```diff
+...
+{
+ "string": [
++ {
++ "name": "camera_reason",
++ "value": "使用相机"
++ },
++ {
++ "name": "microphone_reason",
++ "value": "使用麦克风"
++ },
+ ]
+}
+```
+
+## 使用示例
+
+下面的代码展示了这个库的基本使用场景:
+
+> [!WARNING] 使用时 import 的库名不变。
+
+```js
+import * as React from 'react';
+import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
+import { RNCamera } from "@react-native-ohos/react-native-camera";
+
+export function CameraExample() {
+ const cameraRef = React.useRef(null);
+
+ const takePicture = () => {
+ const camera = cameraRef.current;
+ if (!camera) {
+ return;
+ }
+ camera
+ .takePictureAsync({ quality: 0.5 })
+ .then((photoResult: any) => {
+ console.log('takepicture result:' + (photoResult?.path ?? photoResult?.uri));
+ })
+ .catch((error: unknown) => {
+ console.warn('takepicture failed:', error);
+ });
+ };
+
+ return (
+
+
+
+ 拍照
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1 },
+ cameraPreview: { width: '100%', aspectRatio: 56 / 100 },
+ actionBtn: {
+ margin: 10,
+ padding: 10,
+ backgroundColor: '#1E90FF',
+ borderRadius: 8,
+ alignItems: 'center',
+ },
+ actionBtnText: { color: '#fff', fontSize: 16 },
+});
+```
+
+## 接口说明
+
+> [!TIP] "Platform"列表示该属性在原三方库上支持的平台。
+
+> [!TIP] "HarmonyOS Support"列为 yes 表示 HarmonyOS 平台支持该属性;no 则表示不支持;partially 表示部分支持。使用方法跨平台一致,效果对标 iOS 或 Android 的效果。
+
+### RNCamera
+
+| Name | Description | Type | 函数签名 | Required | Platform | HarmonyOS Support |
+| ---- | ----------- | ---- | -------- | -------- |----------|-------------------|
+| children | 设置子组件 | View | | no | iOS/Android | yes |
+| type | 选择摄像头 | string | | no | iOS/Android | yes |
+| cameraId | 精确指定摄像头设备(getCameraIdsAsync 返回的 id) | string | | no | iOS/Android | yes |
+| flashMode | 设置闪光灯 | string | | no | iOS/Android | yes |
+| exposure | 设置曝光 | number | | no | iOS/Android | yes |
+| autoFocus | 设置自动对焦 | string | | no | iOS/Android | yes |
+| whiteBalance | 白平衡 | string | | no | iOS/Android | yes |
+| captureAudio | 是否开启录音 | boolean | | no | iOS/Android | yes |
+| zoom | 设置缩放比例 | number | | no | iOS/Android | yes |
+| focusDepth | 非自动对焦时,设置对焦值 | number | | no | iOS/Android | yes |
+| maxZoom | 设置最大缩放比例 | number | | no | iOS/Android | yes |
+| pictureSize | 设置默认图片分辨率 | string | | no | iOS/Android | yes |
+| playSoundOnRecord | 录制开始/结束时播放系统提示音 | boolean | | no | Android | no |
+| onCameraReady | 相机就绪回调,无参数 | function | `() => void` | no | iOS/Android | yes |
+| onBarCodeRead | 接收 barcode 扫描数据回调;event 含 data(条码内容)、type(码型)、bounds(位置)等 | function | `(event: BarCodeReadEvent) => void` | no | iOS/Android | yes |
+| onFacesDetected | 接收人脸识别数据回调;response.faces 为人脸数组(harmony 暂不支持) | function | `(response: {faces: Face[]}) => void` | no | iOS/Android | no |
+| onDoubleTap | 双击预览回调;origin 为触点坐标 {x, y}(组件相对坐标) | function | `(origin: Point) => void` | no | iOS/Android | yes |
+| notAuthorizedView | 未授权显示的ui | View | | no | Android | no |
+| pendingAuthorizationView | 正在授权显示的ui | View | | no | Android | no |
+| ratio | 相机比例 | string | | no | Android | no |
+| defaultVideoQuality | 默认视频分辨率 | string | | no | iOS/Android | yes |
+| autoFocusPointOfInterest | 设置自动对焦点(x/y) | Point | | no | iOS/Android | no |
+| useNativeZoom | 启用原生捏合缩放手势 | boolean | | no | iOS/Android | yes |
+| onStatusChange | 相机状态变化回调;event 含 cameraStatus、recordAudioPermissionStatus | function | `(event: {cameraStatus, recordAudioPermissionStatus}) => void` | no | iOS/Android | yes |
+| onMountError | 相机异常回调;error.message 为错误信息 | function | `(error: {message}) => void` | no | iOS/Android | yes |
+| onPictureTaken | 拍照完成回调,无参数 | function | `() => void` | no | iOS/Android | yes |
+| onRecordingStart | 录像开始回调;event.nativeEvent 含 uri、videoOrientation、deviceOrientation | function | `(event: {nativeEvent: {uri, videoOrientation, deviceOrientation}}) => void` | no | iOS/Android | yes |
+| onRecordingEnd | 录像结束回调,无参数 | function | `() => void` | no | iOS/Android | yes |
+| videoStabilizationMode | 视频防抖模式 | string | | no | iOS | no |
+| barCodeTypes | 条码识别类型数组 | BarCodeType[] | | no | iOS/Android | no |
+| detectedImageInEvent | 扫码回调携带原始图像 | boolean | | no | iOS/Android | no |
+| rectOfInterest | 限定条码识别区域 | RectOfInterest | | no | iOS/Android | no |
+| googleVisionBarcodeType | 条码类型(Google Vision) | enum | | no | Android | no |
+| googleVisionBarcodeMode | 条码识别模式(Google Vision) | enum | | no | Android | no |
+| onGoogleVisionBarcodesDetected | Google 条码识别回调 | function | `(event: {type, barcodes, target}) => void` | no | Android | no |
+| onFaceDetectionError | 人脸检测错误回调 | function | `(response: {isOperational}) => void` | no | iOS/Android | no |
+| faceDetectionMode | 人脸检测模式 | string | | no | iOS/Android | no |
+| faceDetectionLandmarks | 人脸特征点检测 | string | | no | iOS/Android | no |
+| faceDetectionClassifications | 人脸分类检测 | string | | no | iOS/Android | no |
+| trackingEnabled | 人脸跟踪 | boolean | | no | iOS/Android | no |
+| onTextRecognized | 文字识别回调 | function | `(response: {textBlocks}) => void` | no | iOS/Android | no |
+| onTap | 单击预览回调;origin 为触点坐标 {x, y} | function | `(origin: Point) => void` | no | iOS | no |
+| onAudioInterrupted | 音频会话中断回调,无参数 | function | `() => void` | no | iOS | no |
+| onAudioConnected | 音频会话连接回调,无参数 | function | `() => void` | no | iOS | no |
+| onSubjectAreaChanged | 主体区域变化回调 | function | `(event: {nativeEvent: {prevPoint: {x, y}}}) => void` | no | iOS | no |
+| useCamera2Api | 使用 Android Camera2 API | boolean | | no | Android | no |
+| playSoundOnCapture | 拍照快门音 | boolean | | no | Android | no |
+| permissionDialogTitle | 权限弹窗标题(已废弃) | string | | no | Android | no |
+| permissionDialogMessage | 权限弹窗文案(已废弃) | string | | no | Android | no |
+| androidCameraPermissionOptions | 相机权限弹窗配置 | object | | no | Android | no |
+| androidRecordAudioPermissionOptions | 录音权限弹窗配置 | object | | no | Android | no |
+| cameraViewDimensions | 扫码区域尺寸(Android) | object | | no | Android | no |
+| keepAudioSession | 卸载时不释放音频会话 | boolean | | no | iOS | no |
+
+### camera
+
+| Name | Description | Type | 函数签名 | Required | Platform | HarmonyOS Support |
+| ---- | ----------- | ---- | -------- | -------- | --------|-------------------|
+| takePictureAsync | 照相;options 可选:quality(0~1)、imageType(jpeg/png)、path 等;resolve 出 TakePictureResponse(width、height、path、pictureOrientation、deviceOrientation) | function | `(options?: TakePictureOptions) => Promise` | no | iOS/Android | yes |
+| recordAsync | 开始录像;options 可选:quality、maxDuration、maxFileSize、mute、path 等;resolve 出 RecordResponse(uri、videoOrientation、deviceOrientation、isRecordingInterrupted) | function | `(options?: RecordOptions) => Promise` | no | iOS/Android | yes |
+| stopRecording | 停止录像,无参数,无返回值;harmony 停录后有转码延迟,待 recordAsync resolve | function | `() => void` | no | iOS/Android | yes |
+| pauseRecording | 暂停录像,无参数,无返回值;仅录像中有效 | function | `() => void` | no | iOS/Android | yes |
+| resumeRecording | 恢复录像,无参数,无返回值;仅暂停后有效 | function | `() => void` | no | iOS/Android | yes |
+| pausePreview | 暂停预览(画面冻结),无参数,无返回值 | function | `() => void` | no | iOS/Android | yes |
+| resumePreview | 恢复预览,无参数,无返回值 | function | `() => void` | no | iOS/Android | yes |
+| getCameraIdsAsync | 获取可用摄像头列表;resolve 出 CameraDeviceInfo[],成员:{ id: string(设备 id,可设给 cameraId)、type: number(摄像头类型)、deviceType?: string } | function | `() => Promise` | no | iOS/Android | yes |
+| getAvailablePictureSizes | 获取可用图片分辨率;resolve 出 string[],如 "1920x1080" | function | `() => Promise` | no | iOS/Android | yes |
+| getSupportedPreviewFpsRange | 获取支持的帧率范围;resolve 出 string[],每项格式 "min,max" | function | `() => Promise` | no | iOS/Android | yes |
+| checkIfVideoIsValid | 校验录像文件是否为有效视频;path 为视频文件路径;返回 true=有效、false=文件不存在或非视频 | function | `(path: string) => Promise` | no | iOS/Android | yes |
+| hasTorch | 查询设备是否支持闪光灯;返回 true/false | function | `() => Promise` | no | iOS/Android | yes |
+| refreshAuthorizationStatus | 重新请求相机/麦克风权限;resolve 后可读取最新授权状态 | function | `() => Promise` | no | iOS/Android | yes |
+| getSupportedRatiosAsync | 获取支持的预览宽高比;resolve 出 string[],如 "4:3"、"16:9" | function | `() => Promise` | no | Android | yes |
+
+## 遗留问题
+
+- [ ] onFacesDetected 人脸检测暂不支持 [issue#8](https://github.com/react-native-oh-library/react-native-camera/issues/8)
+
+
+## 其他
+
+- notAuthorizedView、pendingAuthorizationView、ratio 是 Android 独有属性;harmony 已提供授权时的系统弹窗。
+- playSoundOnRecord 源于 Android 语义(MediaActionSound),OHOS 相机无快门音开关对等 API,当前为 no-op,属性可正常传入不影响其他功能。
+- checkIfVideoIsValid 失败语义平台差异:harmony 对"文件不存在/元数据解析失败"返回 false;Android 上游对加载失败保守返回 true。
+
+## 目录结构
+
+````
+/react-native-camera # 项目根目录
+├── harmony # 鸿蒙适配代码
+│ └── reactNativeCamera.har # har包
+│ └── reactNativeCamera # 鸿蒙适配核心代码
+│ └─ index.ets # 鸿蒙适配代码入口
+│ └─ src/main/ets # ArkTS 实现层
+│ └─ src/main/cpp # C++ 层(NativeCameraPackage/Props/RNCCameraModule 等)
+├── src # RN 代码
+│ └─ index.js # 入口文件
+│ └─ RNCamera.js / FaceDetector.js # 组件与能力封装
+│ └─ NativeCamera.ts / NativeCameraModule.ts / NativeFaceDetector.ts # codegen spec
+├── types # TS 类型定义
+├── README.md # 中文安装使用方法
+├── README_en.md # 英文安装使用方法
+````
+
+## 贡献代码
+
+使用过程中发现任何问题都可以提交 [Issue](https://github.com/react-native-oh-library/react-native-camera/issues),当然,也非常欢迎提交 [PR](https://github.com/react-native-oh-library/react-native-camera/pulls) 。
+
+## 开源协议
+
+本项目基于 [MIT License](https://github.com/react-native-camera/react-native-camera/blob/master/LICENSE) ,请自由地享受和参与开源。
diff --git a/README_en.md b/README_en.md
new file mode 100644
index 000000000..179d3d71b
--- /dev/null
+++ b/README_en.md
@@ -0,0 +1,398 @@
+> Document Template: v0.4.2
+
+
+
react-native-camera
+
+
+This project is based on [react-native-camera](https://github.com/react-native-camera/react-native-camera/tree/v4.2.1).
+
+Please check the matching version information on the Releases page: [@react-native-ohos/react-native-camera Releases](https://github.com/react-native-oh-library/react-native-camera/releases). For older versions not published to npm, please refer to the [Installation Guide](./tgz-usage.md) to install tgz packages.
+
+| Name | Version(Npm Address) | Release Information | Supported RN Version | Supported Autolink | Compile API Version | Community Baseline Version | Source code address |
+| - | - | - | - | - | - | - | - |
+| @react-native-ohos/react-native-camera | [~4.0.0 (In development)](https://www.npmjs.com/package/@react-native-ohos/react-native-camera) | [Releases](https://github.com/react-native-oh-library/react-native-camera/releases) | 0.84.* | Yes | API12+ | v4.2.1 | [sig](https://github.com/react-native-oh-library/react-native-camera/tree/sig) |
+| @react-native-ohos/react-native-camera | [~3.42.0](https://www.npmjs.com/package/@react-native-ohos/react-native-camera) | [Releases](https://github.com/react-native-oh-library/react-native-camera/releases) | 0.82.* | Yes | API12+ | v3.40.0 | [br_rnoh0.82](https://github.com/react-native-oh-library/react-native-camera/tree/br_rnoh0.82) |
+| @react-native-ohos/react-native-camera | [~3.41.1](https://www.npmjs.com/package/@react-native-ohos/react-native-camera) | [Releases](https://github.com/react-native-oh-library/react-native-camera/releases) | 0.77.* | No | API12+ | v3.40.0 | [br_rnoh0.77](https://github.com/react-native-oh-library/react-native-camera/tree/br_rnoh0.77) |
+| @react-native-ohos/react-native-camera | [~3.40.1](https://www.npmjs.com/package/@react-native-ohos/react-native-camera) | [Releases](https://github.com/react-native-oh-library/react-native-camera/releases) | 0.72.* | No | API12+ | v3.40.0 | [br_rnoh0.72](https://github.com/react-native-oh-library/react-native-camera/tree/br_rnoh0.72) |
+
+## Introduction
+
+react-native-camera is a camera component for React Native, which also reads barcodes.
+This repository hosts `@react-native-ohos/react-native-camera`. The current version (4.0.0-beta.1) adapts to the RN 0.84 framework and upgrades the community baseline to react-native-camera v4.2.1: the JS layer integrates via codegen specs (NativeCamera / NativeCameraModule / NativeFaceDetector), and the HarmonyOS side implements preview, photo capture, video recording and barcode scanning based on Camera Kit / AVRecorder.
+
+## Installation
+
+Go to the project directory and execute the following instruction:
+
+**npm**
+
+```bash
+npm install @react-native-ohos/react-native-camera
+```
+
+**yarn**
+
+```bash
+yarn add @react-native-ohos/react-native-camera
+```
+
+## Link
+
+| | Supported Autolink | RN framework version |
+| - | - | - |
+| ~4.0.0 | Yes | 0.84 |
+
+Projects using AutoLink should configure according to this document. Autolink framework guide: https://gitcode.com/openharmony-sig/ohos_react_native/blob/master/docs/en/Autolinking.md
+
+If the version you use supports Autolink and your project has integrated Autolink, you can skip the ManualLink configuration.
+
+ ManualLink: guidance for manually configuring native dependencies
+
+First, open the `harmony` directory of the project with DevEco Studio.
+
+### 1. Overrides RN SDK
+
+To keep the project on a single RN SDK version, add an `overrides` field in the project root `oh-package.json5`, pointing to the RN SDK version required by the project.
+
+```json
+{
+ "overrides": {
+ "@rnoh/react-native-openharmony": "file:./react_native_openharmony.har"
+ }
+}
+```
+
+### 2. Introducing Native Code
+
+Method 1: via har package (recommended)
+
+> [!TIP] The har package is located in the `harmony` folder of the library installation path.
+
+Open `entry/oh-package.json5` and add the following dependency:
+
+```json
+"dependencies": {
+ "@react-native-ohos/react-native-camera": "file:../../node_modules/@react-native-ohos/react-native-camera/harmony/reactNativeCamera.har"
+ }
+```
+
+Click the `sync` button in the top-right corner, or run:
+
+```bash
+cd entry
+ohpm install
+```
+
+Method 2: direct source linking
+
+> [!TIP] For direct source linking, please refer to [link-source-code](https://gitcode.com/CPF-RN/usage-docs/blob/master/en/link-source-code.md)
+
+### 3. Configuring CMakeLists and Introducing NativeCameraPackage
+
+Open `entry/src/main/cpp/CMakeLists.txt` and add:
+
+```diff
++ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
+
+# RNOH_BEGIN: manual_package_linking_1
++ add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-camera/src/main/cpp" ./reactNativeCamera)
+# RNOH_END: manual_package_linking_1
+
+# RNOH_BEGIN: manual_package_linking_2
++ target_link_libraries(rnoh_app PUBLIC rnoh_native_camera)
+# RNOH_END: manual_package_linking_2
+```
+
+Open `entry/src/main/cpp/PackageProvider.cpp` and add:
+
+```diff
+#include "RNOH/PackageProvider.h"
++ #include "NativeCameraPackage.h"
+
+using namespace rnoh;
+
+std::vector> PackageProvider::getPackages(Package::Context ctx) {
+ return {
++ std::make_shared(ctx)
+ };
+}
+```
+
+### 4. Introducing ReactNativeCameraPackage on the ArkTS side
+
+Open `entry/src/main/ets/RNPackagesFactory.ts` and add:
+
+```diff
+ ...
++ import ReactNativeCameraPackage from '@react-native-ohos/react-native-camera';
+
+export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
+ return [
++ new ReactNativeCameraPackage(ctx)
+ ];
+}
+```
+
+> [!TIP] The ArkTS component (ReactCameraView) is provided automatically by the component builder registry inside `ReactNativeCameraPackage` (`createWrappedCustomRNComponentBuilderByComponentNameMap`); the host does not need extra configuration in `buildCustomRNComponent` or `arkTsComponentNames`.
+
+
+### Running
+
+Click the `sync` button in the top-right corner, or run:
+
+```bash
+cd entry
+ohpm install
+```
+
+Then build and run.
+
+## Constraints
+
+### Compatibility
+
+To use this library, a correct React-Native and RNOH version is required, together with matching DevEco Studio and device ROM.
+
+Verified on:
+
+1. RNOH: 0.84.2; SDK: HarmonyOS 6.0.1 Release SDK; IDE: DevEco Studio 6.0.1 Release; ROM: 6.0.0.120 SP7;
+
+### Compilation and Runtime API Requirements
+
+> [!TIP] All versions of this library are version-isolated and support compiling with `API12+` projects and running on `API12+` ROMs.
+
+> [!TIP] The following features depend on specific API versions; compiling with projects or running on ROMs below the specified API version may cause partial feature limitation.
+1. The `whiteBalance` property requires a project compiled with `API20+` and a ROM supporting `API20+` to take effect.
+
+### Permission Requirements
+
+#### Add permissions in `module.json5` under the `entry` directory
+
+Open `entry/src/main/module.json5` and add:
+
+```diff
+...
+"requestPermissions": [
++ {
++ "name": "ohos.permission.CAMERA",
++ "reason": "$string:camera_reason",
++ "usedScene": {
++ "abilities": [
++ "EntryAbility"
++ ],
++ "when":"inuse"
++ }
++ },
++ {
++ "name": "ohos.permission.MICROPHONE",
++ "reason": "$string:microphone_reason",
++ "usedScene": {
++ "abilities": [
++ "EntryAbility"
++ ],
++ "when":"inuse"
++ }
++ },
+]
+```
+
+#### Add the permission rationale strings under the `entry` directory
+
+Open `entry/src/main/resources/base/element/string.json` and add:
+
+```diff
+...
+{
+ "string": [
++ {
++ "name": "camera_reason",
++ "value": "Use the camera"
++ },
++ {
++ "name": "microphone_reason",
++ "value": "Use the microphone"
++ },
+ ]
+}
+```
+
+## Example
+
+The following code shows the basic usage of this library:
+
+> [!WARNING] The import name stays unchanged.
+
+```js
+import * as React from 'react';
+import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
+import { RNCamera } from "@react-native-ohos/react-native-camera";
+
+export function CameraExample() {
+ const cameraRef = React.useRef(null);
+
+ const takePicture = () => {
+ const camera = cameraRef.current;
+ if (!camera) {
+ return;
+ }
+ camera
+ .takePictureAsync({ quality: 0.5 })
+ .then((photoResult: any) => {
+ console.log('takepicture result:' + (photoResult?.path ?? photoResult?.uri));
+ })
+ .catch((error: unknown) => {
+ console.warn('takepicture failed:', error);
+ });
+ };
+
+ return (
+
+
+
+ Take Photo
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1 },
+ cameraPreview: { width: '100%', aspectRatio: 56 / 100 },
+ actionBtn: {
+ margin: 10,
+ padding: 10,
+ backgroundColor: '#1E90FF',
+ borderRadius: 8,
+ alignItems: 'center',
+ },
+ actionBtnText: { color: '#fff', fontSize: 16 },
+});
+```
+
+## Properties
+
+> [!TIP] The "Platform" column indicates the platforms supported by the property in the original third-party library.
+
+> [!TIP] In the "HarmonyOS Support" column, yes means the property is supported on HarmonyOS; no means not supported; partially means partially supported. Usage is consistent across platforms, benchmarked against iOS or Android behavior.
+
+### RNCamera
+
+| Name | Description | Type | Function Signature | Required | Platform | HarmonyOS Support |
+| ---- | ----------- | ---- | ------------------ | -------- |----------|-------------------|
+| children | Set child components | View | | no | iOS/Android | yes |
+| type | Select camera | string | | no | iOS/Android | yes |
+| cameraId | Precisely specify the camera device (the id returned by getCameraIdsAsync) | string | | no | iOS/Android | yes |
+| flashMode | Set flash mode | string | | no | iOS/Android | yes |
+| exposure | Set exposure | number | | no | iOS/Android | yes |
+| autoFocus | Set auto focus | string | | no | iOS/Android | yes |
+| whiteBalance | White balance | string | | no | iOS/Android | yes |
+| captureAudio | Enable audio recording | boolean | | no | iOS/Android | yes |
+| zoom | Set zoom ratio | number | | no | iOS/Android | yes |
+| focusDepth | Set focus value in non-auto-focus mode | number | | no | iOS/Android | yes |
+| maxZoom | Set max zoom ratio | number | | no | iOS/Android | yes |
+| pictureSize | Set default picture resolution | string | | no | iOS/Android | yes |
+| playSoundOnRecord | Play system sound at recording start/stop | boolean | | no | Android | no |
+| onCameraReady | Camera ready callback, no arguments | function | `() => void` | no | iOS/Android | yes |
+| onBarCodeRead | Barcode scanning callback; event contains data (barcode content), type (barcode format), bounds (position) | function | `(event: BarCodeReadEvent) => void` | no | iOS/Android | yes |
+| onFacesDetected | Face detection callback; response.faces is the face array (not yet supported on harmony) | function | `(response: {faces: Face[]}) => void` | no | iOS/Android | no |
+| onDoubleTap | Double tap on preview callback; origin is the touch point {x, y} (component-relative) | function | `(origin: Point) => void` | no | iOS/Android | yes |
+| notAuthorizedView | UI shown when not authorized | View | | no | Android | no |
+| pendingAuthorizationView | UI shown while authorizing | View | | no | Android | no |
+| ratio | Camera ratio | string | | no | Android | no |
+| defaultVideoQuality | Default video quality | string | | no | iOS/Android | yes |
+| autoFocusPointOfInterest | Set auto focus point (x/y) | Point | | no | iOS/Android | no |
+| useNativeZoom | Enable native pinch-to-zoom gesture | boolean | | no | iOS/Android | yes |
+| onStatusChange | Camera status change callback; event contains cameraStatus, recordAudioPermissionStatus | function | `(event: {cameraStatus, recordAudioPermissionStatus}) => void` | no | iOS/Android | yes |
+| onMountError | Camera error callback; error.message is the error message | function | `(error: {message}) => void` | no | iOS/Android | yes |
+| onPictureTaken | Picture taken callback, no arguments | function | `() => void` | no | iOS/Android | yes |
+| onRecordingStart | Recording start callback; event.nativeEvent contains uri, videoOrientation, deviceOrientation | function | `(event: {nativeEvent: {uri, videoOrientation, deviceOrientation}}) => void` | no | iOS/Android | yes |
+| onRecordingEnd | Recording end callback, no arguments | function | `() => void` | no | iOS/Android | yes |
+| videoStabilizationMode | Video stabilization mode | string | | no | iOS | no |
+| barCodeTypes | Barcode type array | BarCodeType[] | | no | iOS/Android | no |
+| detectedImageInEvent | Include raw image in barcode callback | boolean | | no | iOS/Android | no |
+| rectOfInterest | Limit barcode recognition area | RectOfInterest | | no | iOS/Android | no |
+| googleVisionBarcodeType | Barcode type (Google Vision) | enum | | no | Android | no |
+| googleVisionBarcodeMode | Barcode recognition mode (Google Vision) | enum | | no | Android | no |
+| onGoogleVisionBarcodesDetected | Google Vision barcode callback | function | `(event: {type, barcodes, target}) => void` | no | Android | no |
+| onFaceDetectionError | Face detection error callback | function | `(response: {isOperational}) => void` | no | iOS/Android | no |
+| faceDetectionMode | Face detection mode | string | | no | iOS/Android | no |
+| faceDetectionLandmarks | Face landmarks detection | string | | no | iOS/Android | no |
+| faceDetectionClassifications | Face classification detection | string | | no | iOS/Android | no |
+| trackingEnabled | Face tracking | boolean | | no | iOS/Android | no |
+| onTextRecognized | Text recognition callback | function | `(response: {textBlocks}) => void` | no | iOS/Android | no |
+| onTap | Single tap on preview callback; origin is the touch point {x, y} | function | `(origin: Point) => void` | no | iOS | no |
+| onAudioInterrupted | Audio session interruption callback, no arguments | function | `() => void` | no | iOS | no |
+| onAudioConnected | Audio session connected callback, no arguments | function | `() => void` | no | iOS | no |
+| onSubjectAreaChanged | Subject area changed callback | function | `(event: {nativeEvent: {prevPoint: {x, y}}}) => void` | no | iOS | no |
+| useCamera2Api | Use Android Camera2 API | boolean | | no | Android | no |
+| playSoundOnCapture | Shutter sound on capture | boolean | | no | Android | no |
+| permissionDialogTitle | Permission dialog title (deprecated) | string | | no | Android | no |
+| permissionDialogMessage | Permission dialog message (deprecated) | string | | no | Android | no |
+| androidCameraPermissionOptions | Camera permission dialog config | object | | no | Android | no |
+| androidRecordAudioPermissionOptions | Record-audio permission dialog config | object | | no | Android | no |
+| cameraViewDimensions | Scan area dimensions (Android) | object | | no | Android | no |
+| keepAudioSession | Keep audio session on unmount | boolean | | no | iOS | no |
+
+### camera
+
+| Name | Description | Type | Function Signature | Required | Platform | HarmonyOS Support |
+| ---- | ----------- | ---- | ------------------ | -------- | --------|-------------------|
+| takePictureAsync | Take a photo; optional options: quality (0~1), imageType (jpeg/png), path, etc.; resolves with TakePictureResponse (width, height, path, pictureOrientation, deviceOrientation) | function | `(options?: TakePictureOptions) => Promise` | no | iOS/Android | yes |
+| recordAsync | Start recording; optional options: quality, maxDuration, maxFileSize, mute, path, etc.; resolves with RecordResponse (uri, videoOrientation, deviceOrientation, isRecordingInterrupted) | function | `(options?: RecordOptions) => Promise` | no | iOS/Android | yes |
+| stopRecording | Stop recording, no arguments, no return value; on harmony there is a transcoding delay before recordAsync resolves | function | `() => void` | no | iOS/Android | yes |
+| pauseRecording | Pause recording, no arguments, no return value; valid only while recording | function | `() => void` | no | iOS/Android | yes |
+| resumeRecording | Resume recording, no arguments, no return value; valid only after pause | function | `() => void` | no | iOS/Android | yes |
+| pausePreview | Pause preview (frame freeze), no arguments, no return value | function | `() => void` | no | iOS/Android | yes |
+| resumePreview | Resume preview, no arguments, no return value | function | `() => void` | no | iOS/Android | yes |
+| getCameraIdsAsync | Get available cameras; resolves with CameraDeviceInfo[], members: { id: string (device id, settable to cameraId), type: number (camera type), deviceType?: string } | function | `() => Promise` | no | iOS/Android | yes |
+| getAvailablePictureSizes | Get available picture sizes; resolves with string[] such as "1920x1080" | function | `() => Promise` | no | iOS/Android | yes |
+| getSupportedPreviewFpsRange | Get supported fps ranges; resolves with string[], each item "min,max" | function | `() => Promise` | no | iOS/Android | yes |
+| checkIfVideoIsValid | Validate a recorded file; path is the video file path; returns true = valid, false = not found or not a video | function | `(path: string) => Promise` | no | iOS/Android | yes |
+| hasTorch | Query flash support; returns true/false | function | `() => Promise` | no | iOS/Android | yes |
+| refreshAuthorizationStatus | Re-request camera/microphone permission; after resolve the latest authorization status can be read | function | `() => Promise` | no | iOS/Android | yes |
+| getSupportedRatiosAsync | Get supported preview aspect ratios; resolves with string[] such as "4:3", "16:9" | function | `() => Promise` | no | Android | yes |
+
+## Known Issues
+
+- [ ] onFacesDetected (face detection) is not yet supported [issue#8](https://github.com/react-native-oh-library/react-native-camera/issues/8)
+
+
+## Others
+
+- notAuthorizedView, pendingAuthorizationView and ratio are Android-only properties; HarmonyOS provides the system permission dialog when requesting authorization.
+- playSoundOnRecord originates from Android semantics (MediaActionSound); the OHOS camera has no shutter-sound equivalent API, so it is currently a no-op. The property can be passed normally without affecting other features.
+- checkIfVideoIsValid failure semantics differ by platform: HarmonyOS returns false for "file not found / metadata parsing failure"; the Android upstream conservatively returns true on load failure.
+
+## Directory Structure
+
+````
+/react-native-camera # Project root
+├── harmony # HarmonyOS adaptation code
+│ └── reactNativeCamera.har # har package
+│ └── reactNativeCamera # Core HarmonyOS adaptation code
+│ └─ index.ets # Entry of the HarmonyOS adaptation code
+│ └─ src/main/ets # ArkTS implementation layer
+│ └─ src/main/cpp # C++ layer (NativeCameraPackage/Props/RNCCameraModule, etc.)
+├── src # RN code
+│ └─ index.js # Entry file
+│ └─ RNCamera.js / FaceDetector.js # Component and capability wrappers
+│ └─ NativeCamera.ts / NativeCameraModule.ts / NativeFaceDetector.ts # codegen specs
+├── types # TS type definitions
+├── README.md # Chinese installation and usage guide
+├── README_en.md # English installation and usage guide
+````
+
+## Contributing
+
+If you find any problem during usage, feel free to submit an [Issue](https://github.com/react-native-oh-library/react-native-camera/issues); PRs are also welcome ([Pull Requests](https://github.com/react-native-oh-library/react-native-camera/pulls)).
+
+## License
+
+This project is based on the [MIT License](https://github.com/react-native-camera/react-native-camera/blob/master/LICENSE), please feel free to enjoy and participate in open source.
diff --git a/harmony/reactNativeCamera.har b/harmony/reactNativeCamera.har
index 83fa5482632b42512c1dada4cfb1060c3a3c20af..864753264a3b0fb29cd92d5f8a56713d716ad828 100644
GIT binary patch
literal 50413
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