> [!TIP] [Gitee 地址](https://e.gitee.com/kunyuan-hongke/projects/723653/repos/kunyuan-hongke/react-native-camera/sources)
## 介绍
本项目基于[react-native-camera](https://github.com/react-native-camera/react-native-camera/tree/v3.30.0)开发。
## 安装与使用
请到三方库的 Releases 发布地址查看配套的版本信息:[@ohmi/react-native-camera Releases](https://e.gitee.com/kunyuan-hongke/projects/723653/repos/kunyuan-hongke/react-native-camera/releases) 。对于未发布到npm的旧版本,请参考[安装指南](https://gitee.com/react-native-oh-library/usage-docs/blob/master/zh-cn/tgz-usage.md)安装tgz包。
进入到工程目录并输入以下命令:
#### npm
```bash
npm install @ohmi/react-native-camera
```
#### yarn
```bash
yarn add @ohmi/react-native-camera
```
下面的代码展示了这个库的基本使用场景:
> [!WARNING] 使用时 import 的库名不变。
### photo example
```js
import React, {useState, useRef} from 'react';
import {StyleSheet, Text, View, Button, Image} from 'react-native';
import {RNCamera} from 'react-native-camera';
export const PhotoDemo = () => {
const cameraRef = useRef(null);
const [capturedImage, setCapturedImage] = useState(null);
const takePicture = async () => {
if (cameraRef.current) {
try {
const options = {quality: 0.5, base64: false};
const data = await cameraRef.current.takePictureAsync(options);
setCapturedImage(data.uri);
} catch (error) {
console.error('拍照出错:', error);
}
}
};
return (
{capturedImage ? (
) : (
)}
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
preview: {
width: 300,
height: 400,
marginBottom: 20,
},
capturedImage: {
width: 300,
height: 400,
marginBottom: 20,
},
});
```
### video example
```js
import React, {useState, useRef} from 'react';
import {StyleSheet, Text, View, Button} from 'react-native';
import {RNCamera} from 'react-native-camera';
export const VideoDemo = () => {
const cameraRef = useRef(null);
const [isRecording, setIsRecording] = useState(false);
const [isPaused, setIsPaused] = useState(false);
const [videoUri, setVideoUri] = useState(null);
const startRecording = async () => {
if (cameraRef.current) {
try {
const options = {quality: RNCamera.Constants.VideoQuality['720p']};
const videoRecordPromise = cameraRef.current.recordAsync(options);
if (videoRecordPromise) {
setIsRecording(true);
const data = await videoRecordPromise;
setVideoUri(data.uri);
setIsRecording(false);
}
} catch (error) {
console.error('录制视频出错:', error);
}
}
};
const stopRecording = () => {
if (cameraRef.current) {
cameraRef.current.stopRecording();
setIsRecording(false);
}
};
const pauseRecording = () => {
if (cameraRef.current) {
cameraRef.current.pausePreview();
setIsPaused(true);
}
};
const resumeRecording = () => {
if (cameraRef.current) {
cameraRef.current.resumePreview();
setIsPaused(false);
}
};
return (
{}}
/>
{!isRecording && }
{isRecording && !isPaused && (
)}
{isRecording && isPaused && (
)}
{isRecording && }
{videoUri && (
视频保存路径: {videoUri}
)}
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
preview: {
width: 300,
height: 400,
marginBottom: 20,
},
buttonContainer: {
flexDirection: 'row',
justifyContent: 'space-around',
width: '100%',
backgroundColor: '#000',
padding: 4,
},
videoUriText: {
textAlign: 'center',
},
videoPlayer: {
width: 300,
height: 400,
marginBottom: 20,
},
});
```
## Link
目前 HarmonyOS 暂不支持 AutoLink,所以 Link 步骤需要手动配置。
首先需要使用 DevEco Studio 打开项目里的 HarmonyOS 工程 `harmony`
### 1.在工程根目录的 `oh-package.json` 添加 overrides字段
```json
{
...
"overrides": {
"@rnoh/react-native-openharmony" : "./react_native_openharmony"
}
}
```
### 2.引入原生端代码
目前有两种方法:
1. 通过 har 包引入(在 IDE 完善相关功能后该方法会被遗弃,目前首选此方法);
2. 直接链接源码。
方法一:通过 har 包引入 (推荐)
> [!TIP] har 包位于三方库安装路径的 `harmony` 文件夹下。
打开 `entry/oh-package.json5`,添加以下依赖
```json
"dependencies": {
"@rnoh/react-native-openharmony": "file:../react_native_openharmony",
"@ohmi/react-native-camera": "file:../../node_modules/@ohmi/react-native-camera/harmony/camera.har"
}
```
点击右上角的 `sync` 按钮
或者在终端执行:
```bash
cd entry
ohpm install
```
方法二:直接链接源码
> [!TIP] 如需使用直接链接源码,请参考[直接链接源码说明](https://gitee.com/react-native-oh-library/usage-docs/blob/master/zh-cn/link-source-code.md)
### 3.配置 CMakeLists 和引入 RTNCameraPackage
打开 `entry/src/main/cpp/CMakeLists.txt`,添加:
```diff
project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
set(LOG_VERBOSITY_LEVEL 1)
set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments")
set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
set(WITH_HITRACE_SYSTRACE 1) # for other CMakeLists.txt files to use
add_compile_definitions(WITH_HITRACE_SYSTRACE)
add_subdirectory("${RNOH_CPP_DIR}" ./rn)
# RNOH_BEGIN: manual_package_linking_1
add_subdirectory("../../../../sample_package/src/main/cpp" ./sample-package)
+ add_subdirectory("${OH_MODULES}/@ohmi/react-native-camera/src/main/cpp" ./camera)
# RNOH_END: manual_package_linking_1
file(GLOB GENERATED_CPP_FILES "./generated/*.cpp")
add_library(rnoh_app SHARED
${GENERATED_CPP_FILES}
"./PackageProvider.cpp"
"${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_link_libraries(rnoh_app PUBLIC rnoh)
# RNOH_BEGIN: manual_package_linking_2
target_link_libraries(rnoh_app PUBLIC rnoh_sample_package)
+ target_link_libraries(rnoh_app PUBLIC rnoh_camera)
# RNOH_END: manual_package_linking_2
```
打开 `entry/src/main/cpp/PackageProvider.cpp`,添加:
```diff
#include "RNOH/PackageProvider.h"
#include "generated/RNOHGeneratedPackage.h"
#include "SamplePackage.h"
+ #include "RTNCameraPackage.h"
using namespace rnoh;
std::vector> PackageProvider::getPackages(Package::Context ctx) {
return {
std::make_shared(ctx),
std::make_shared(ctx),
+ std::make_shared(ctx),
};
}
```
### 4.在 ArkTs 侧引入 RTNCameraView 组件
找到 `function buildCustomRNComponent()`,一般位于 `entry/src/main/ets/pages/index.ets` 或 `entry/src/main/ets/rn/LoadBundle.ets`,添加:
```diff
...
+ import { RTNCameraView } from "@ohmi/react-native-camera";
@Builder
export function buildCustomRNComponent(ctx: ComponentBuilderContext) {
...
+ if (ctx.componentName === RTNCameraView.NAME) {
+ RTNCameraView({
+ ctx: ctx.rnComponentContext,
+ tag: ctx.tag,
+ })
+ }
...
}
...
```
在`entry/src/main/ets/pages/index.ets`中,如果当前文件中存在`arkTsComponentNames`数组(后续版本新增内容),则需要在其中追加:`RTNCameraView.NAME`;
```ts
...
const arkTsComponentNames: Array = [..., RTNCameraView.NAME];
...
```
### 5.在 ArkTs 侧引入 RTNCameraPackage
打开 `entry/src/main/ets/RNPackagesFactory.ts`,添加:
```diff
...
+ import { RTNCameraPackage } from "@ohmi/react-native-camera/ts";
export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
return [
new SamplePackage(ctx),
+ new RTNCameraPackage(ctx),
];
}
```
### 6.运行
点击右上角的 `sync` 按钮
或者在终端执行:
```bash
cd entry
ohpm install
```
然后编译、运行即可。
## 约束与限制
### 兼容性
本文档内容基于以下版本验证通过:
RNOH:0.72.50; SDK:5.0.2.126 ; IDE:DevEco Studio 5.0.7.210; ROM:5.0.0.135;
### 权限要求
以下权限中有`system_basic` 权限,而默认的应用权限是 `normal` ,只能使用 `normal` 等级的权限,所以可能会在安装hap包时报错**9568289**,请参考 [文档](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/bm-tool-V5#ZH-CN_TOPIC_0000001884757326__%E5%AE%89%E8%A3%85hap%E6%97%B6%E6%8F%90%E7%A4%BAcode9568289-error-install-failed-due-to-grant-request-permissions-failed) 修改应用等级为 `system_basic`
#### 在 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": "使用麦克风"
+ },
]
}
```
### 鸿蒙属性要求
onRecordingStart:开始录制视频的回调,(由于鸿蒙平台差异,如果是视频录制模式,此参数必填,拍照模式不用填写),可参照视频录制功能demo实现。
## 属性
> [!TIP] "Platform"列表示该属性在原三方库上支持的平台。
> [!TIP] "HarmonyOS Support"列为 yes 表示 HarmonyOS 平台支持该属性;no 则表示不支持;partially 表示部分支持。使用方法跨平台一致,效果对标 iOS 或 Android 的效果。
| Name | Description | Type | Required | Platform | HarmonyOS Support |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------- | -------- | -------- | ----------------- |
| zoom | This property specifies the zoom value of the camera. Ranges from 0 to 1. Default to 0 | number | no | All | yes |
| maxZoom | The maximum zoom value of the camera. Defaults to 0. | number | no | All | yes |
| type | This property defines which camera on the phone the component is using. Possible values: | 'front'`/`'back' | no | All | yes |
| focusMode | Camera focus mode. Default: on | 'on'`/`'off' | no | All | yes |
| zoomMode | Enable the pinch to zoom gesture. Default: on | 'on'`/`'off' | no | All | yes |
| zoom | Control the zoom. Default: 1.0 | number | no | All | yes |
| maxZoom | Maximum zoom allowed (but not beyond what camera allows). Default: undefined (camera default max) | number | no | All | yes |
| cameraId | For selecting from multiple cameras on Android devices. See 2492 for more info. Can be retrieved with | string | no | All | yes |
| flashMode | Determines the state of the camera flash. Has the following possible states | string | no | All | yes |
| ratio | A string representing the camera ratio in the format 'height:width'. Default is `"4:3"`. | string | no | All | yes |
| pictureSize | This prop has a different behaviour for Android and iOS and should rarely be set. | string | no | All | yes |
| autoFocusPointOfInterest | Setting this property causes the auto focus feature of the camera to attempt to focus on the part of the image at this coordiate. | object | no | all | yes |
| captureAudio | Android only. Enable or disable the shutter sound when capturing a photo. Default: `true` | Boolean | no | Android | yes |
| ratioOverlay | Show a guiding overlay in the camera preview for the selected ratio. Does not crop image as of v9.0. Example: '16:9' | String | no | iOS | yes |
| ratioOverlayColor | Any color with alpha. Default: '#ffffff77' | String | no | All | yes |
| resetFocusTimeout | Dismiss tap to focus after this many milliseconds. Default 0 (disabled). Example: 5000 is 5 seconds. | Number | no | All | yes |
| keepAudioSession | (iOS Only) When the camera is unmounted, it will release any audio session it acquired (if `captureAudio=true`) so other media can continue playing. However, this might not be always desirable (e.g., if video is played afterwards) and can be disabled by setting it to `true`. Setting this to `true`, means your app will not release the audio session. Note: other apps might still "steal" the audio session from your app. | Boolean | no | iOS | no |
| focusDepth | Manually set camera focus. Only works with `autoFocus` off. The value 0 is minimum focus depth, 1 is maximum focus depth. For a medium focus depth, for example, you could use 0.5. | number | no | all | no |
| whiteBalance | A camera’s white balance setting allows you to control the color temperature in your photos by cooling down or warming up the colors. | string | no | all | yes |
| exposure | Value: float from `0` to `1.0`, or `-1` (default) for auto. | string | no | all | yes |
| useNativeZoom | Boolean to turn on native pinch to zoom. Works with the `maxZoom` property on iOS. | Boolean | no | iOS | yes |
| permissionDialogTitle | Android Permissions dialog title | sting | no | android | no |
| permissionDialogMessage | Android Permissions dialog message | string | no | android | no |
| androidRecordAudioPermissionOptions | Android recording permission options | sting | no | android | no |
| androidCameraPermissionOptions | Android camera permission options | sting | no | android | no |
| notAuthorizedView | By default a `Camera not authorized` message will be displayed when access to the camera has been denied, if set displays the passed react element instead of the default one. | element | no | all | yes |
| pendingAuthorizationView | By default a will be displayed while the component is waiting for the user to grant/deny access to the camera, if set displays the passed react element instead of the default one. | element | no | all | yes |
| rectOfInterest | An `{x: , y:, width:, height: }` object which defines the rect of interst as normalized coordinates from `(0,0)` top left corner to `(1,1)` bottom right corner. | object | no | all | no |
| cameraViewDimensions | An `{width:, height: }` object which defines the width and height of the cameraView. This prop is used to adjust the effect of Aspect Raio for rectOfInterest area on Android | object | no | android | no |
| playSoundOnCapture | Boolean to turn on or off the camera's shutter sound (default false). Note that in some countries, the shutter sound cannot be turned off. | boolean | no | all | yes |
| playSoundOnRecord | Boolean to turn on or off the camera's record sound (default false) | boolean | no | all | yes |
| videoStabilizationMode | The video stabilization mode used for a video recording. | string | no | all | no |
| defaultVideoQuality | This option specifies the quality of the video to be taken. The possible values are:2160p,1080p,720p,480p,4:3,288p | string | no | all | yes |
| barCodeTypes | An array of barcode types to search for. Defaults to all types listed above. No effect if `onBarCodeRead` is undefined. | string | no | all | yes |
| googleVisionBarcodeType | Like `barCodeTypes`, but applies to the Firebase MLKit barcode detector. | string | no | all | partially |
| googleVisionBarcodeMode | Google Visual bar code pattern | string | no | all | no |
| detectedImageInEvent | When `detectedImageInEvent` is `false` (default), `onBarCodeRead` / `onBarcodesDetected` only gives metadata, but not the image (bytes/base64) itself. | boolean | no | all | yes |
| faceDetectionMode | Face detection mode | string | no | all | no |
| faceDetectionLandmarks | Face detection coordinates | object | no | all | partially |
| faceDetectionClassifications | Facial examination type | string | no | all | no |
| onSubjectAreaChanged | This event is triggered when substantial changes are detected in the following objects | function | no | ios | no |
| onCameraReady | Camera ready callback | function | no | all | yes |
| onMountError | An incorrect callback occurred | function | no | all | yes |
| onStatusChange | Callbacks for camera state changes | function | no | all | yes |
| onAudioInterrupted | A callback when an audio session is interrupted or cannot be started for any reason | function | no | ios | no |
| onAudioConnected | Audio is connected to a callback | function | no | ios | yes |
| onPictureTaken | A callback when taking a photo | function | no | ios | yes |
| onRecordingStart | Start the callback for recording the video | function | no | ios | yes |
| onRecordingEnd | The callback to stop recording the video | function | no | ios | yes |
| onTap | Touch the camera preview view's callback | function | no | all | yes |
| onDoubleTap | Double-click the callback for the camera preview view | function | no | all | yes |
| onBarCodeRead | Scan successful callback | function | no | all | yes |
| onGoogleVisionBarcodesDetected | Callback when a Google visual barcode is detected | function | no | all | yes |
| onFaceDetectionError | Face detection error callback | function | no | all | yes |
| onFacesDetected | Face detection callback | function | no | all | yes |
| onTextRecognized | Check the callback when the text is reached | function | no | all | yes |
## 静态方法
| Name | Description | Type | Required | Platform | HarmonyOS Support |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | -------- | -------- | ----------------- |
| detectFacesAsync | Detect faces in local images. | Promise | No | All | Yes |
| takePictureAsync | Returns a promise with TakePictureResponse. | Promise | No | All | Yes |
| recordAsync | Returns a promise with RecordResponse. | Promise | All | Yes | Yes |
| refreshAuthorizationStatus | Allows to make RNCamera check Permissions again and set status accordingly. | Promise | All | Yes | Yes |
| stopRecording | Should be called after recordAsync() to make the promise be fulfilled and get the video uri.. | Promise | All | Yes | Yes |
| pausePreview | Pauses the preview. The preview can be resumed again by using resumePreview(). | Promise | All | Yes | Yes |
| resumePreview | Resumes the preview after pausePreview() has been called. | Promise | All | Yes | Yes |
| getSupportedRatiosAsync | Android only. Returns a promise. The promise will be fulfilled with an object with an array containing strings with all camera aspect ratios supported by the device. | Promise | All | Yes | Yes |
| checkIfVideoIsValid | Check that the video is valid | Promise | All | Yes | Yes |
| getCameraIdsAsync | Returns a promise. The promise will be fulfilled with an array containing objects with all camera IDs and type supported by the device. | Promise | All | Yes | Yes |
| isRecording | iOS only. Returns a promise. The promise will be fulfilled with a boolean indicating if currently recording is started or stopped. | Promise | All | Yes | Yes |
## 遗留问题
- [ ] onSubjectAreaChanged 不支持:当检测到以下对象发生实质性更改时将触发此事件 [issue#1]()
- [ ] keepAudioSession 不支持:保持音频会话 [issue#2]()
- [ ] whiteBalance:不支持白平衡 [issue#3]()
- [ ] permissionDialogTitle,不支持:配置安卓权限对话框标题 [issue#4]()
- [ ] permissionDialogMessage,不支持:配置安卓权限对话框标题 [issue#5]()
- [ ] androidRecordAudioPermissionOptions,不支持:配置安卓录音权限选项 [issue#6]()
- [ ] androidCameraPermissionOptions,不支持:配置安卓相机权限选项 [issue#7]()
- [ ] rectOfInterest,不支持:配置感兴趣的矩形区域属性 [issue#8]()
- [ ] googleVisionBarcodeMode [issue#9]()
- [ ] cameraViewDimensions,不支持:设置相机尺寸属性 [issue#10]()
- [ ] googleVisionBarcodeMode,不支持:设置谷歌视觉条码模式 [issue#11]()
- [ ] faceDetectionMode,不支持:设置人脸检测模式 [issue#12]()
- [ ] faceDetectionClassifications,不支持:设置面部检查类型 [issue#13]()
- [ ] recordAsync,不支持:异步录制视频设置option[issue#14]()
- [ ] faceDetectionLandmarks属性,部分支持缺少脸颊耳朵坐标点[issue#15]()
- [ ] onGoogleVisionBarcodesDetected回调函数,兼容性支持,只返回onBarCodeRead部分属性[issue#16]()
- [ ] googleVisionBarcodeType属性,兼容性支持barCodeTypes部分支持类型[issue#17]()
## 其他
## 开源协议
本项目基于 [The MIT License (MIT)](https://github.com/teslamotors/react-native-camera-kit/blob/master/LICENSE) ,请自由地享受和参与开源。