从Expo转RN CLI:如何用react-native-vision-camera替代expo-camera(Android)
React Native CLI 迁移:react-native-vision-camera 替代 expo-camera 解决 Android 黑屏问题
问题背景
我之前使用 Expo 开发项目,现迁移至 React Native CLI,希望用 react-native-vision-camera 替代 expo-camera 实现原有人脸检测+拍照功能,但 Android 端出现黑屏现象,求解决方案。原 Expo 代码如下:
import { Camera } from 'expo-camera'; import { TouchableOpacity, Text, View, ActivityIndicator } from 'react-native'; import { useState, useEffect, useRef } from "react"; import * as FaceDetector from 'expo-face-detector'; export default function CameraPage({ navigation }) { const [hasPermission, setHasPermission] = useState(null); const cameraRef = useRef(null); const [faceData, setFaceData] = useState([]); useEffect(() => { (async () => { const { status } = await Camera.requestCameraPermissionsAsync(); setHasPermission(status === 'granted'); })(); }, []); if (hasPermission === null) { return <View />; } if (hasPermission === false) { return <Text>No access to camera</Text>; } const handleTakePicture = async () => { if (faceData.length === 0) { alert('No Face') } else if (cameraRef.current) { const photo = await cameraRef.current.takePictureAsync(); console.log(photo.uri) if (!photo.cancelled) { navigation.navigate('addphoto', { Image: photo.uri }); } } } const handleFacesDetected = ({ faces }) => { setFaceData(faces); } return ( <View style={{ flex: 1, backgroundColor: 'black' }}> <Camera onFacesDetected={handleFacesDetected} faceDetectorSettings={{ mode: FaceDetector.FaceDetectorMode.fast, detectLandmarks: FaceDetector.FaceDetectorLandmarks.none, runClassifications: FaceDetector.FaceDetectorClassifications.none, minDetectionInterval: 100, tracking: true, }} style={{ borderTopLeftRadius: 30, borderTopRightRadius: 30, borderBottomLeftRadius: 30, borderBottomRightRadius: 30, overflow: 'hidden', width: '130%', aspectRatio: 1, }} type={Camera.Constants.Type.front} ref={cameraRef} > <View style={{ flex: 1, backgroundColor: 'transparent', flexDirection: 'row' }}> </View> </Camera> <TouchableOpacity style={{ alignSelf: 'center', alignItems: 'center', width: 90, height: 90, borderRadius: 500, marginTop: '30%', marginLeft: '5%', borderColor: '#5A5A5A', borderWidth: 6, }} onPress={handleTakePicture} > <View style={{ opacity: 0.5 }} /> </TouchableOpacity> </View> ); }
解决方案
1. 完整替代代码
以下是适配 react-native-vision-camera 的实现,完全匹配原 Expo 功能:
import { TouchableOpacity, Text, View } from 'react-native'; import { useState, useEffect, useRef } from "react"; import { Camera, useCameraPermissions, useCameraDevice, takePhoto } from 'react-native-vision-camera'; import { useFaceDetection } from 'react-native-vision-camera-face-detector'; export default function CameraPage({ navigation }) { const [hasPermission, setHasPermission] = useState(null); const cameraRef = useRef(null); const [faceData, setFaceData] = useState([]); // 处理相机权限 const { permission, requestPermission } = useCameraPermissions(); useEffect(() => { const getPermission = async () => { const res = await requestPermission(); setHasPermission(res === 'granted'); }; if (permission === 'not-determined') getPermission(); else setHasPermission(permission === 'granted'); }, [permission]); if (hasPermission === null) { return <View />; } if (hasPermission === false) { return <Text>无相机访问权限</Text>; } // 获取前置摄像头设备 const device = useCameraDevice('front'); if (!device) return <Text>找不到前置摄像头</Text>; // 人脸检测配置(匹配原 Expo 参数) const frameProcessor = useFaceDetection({ mode: 'fast', detectLandmarks: 'none', runClassifications: 'none', minDetectionInterval: 100, tracking: true, }, ({ faces }) => { setFaceData(faces); }); // 拍照逻辑 const handleTakePicture = async () => { if (faceData.length === 0) { alert('未检测到人脸'); return; } if (!cameraRef.current) return; try { const photo = await takePhoto(cameraRef.current, { quality: 0.8, }); console.log(photo.path); navigation.navigate('addphoto', { Image: photo.path }); } catch (error) { console.error('拍照失败:', error); } }; return ( <View style={{ flex: 1, backgroundColor: 'black' }}> {device && ( <Camera ref={cameraRef} style={{ borderTopLeftRadius: 30, borderTopRightRadius: 30, borderBottomLeftRadius: 30, borderBottomRightRadius: 30, overflow: 'hidden', width: '130%', aspectRatio: 1, }} device={device} isActive={true} // 必须设置为true激活预览 frameProcessor={frameProcessor} frameProcessorFps={5} // 控制人脸检测帧率,避免性能问题 /> )} <TouchableOpacity style={{ alignSelf: 'center', alignItems: 'center', width: 90, height: 90, borderRadius: 500, marginTop: '30%', marginLeft: '5%', borderColor: '#5A5A5A', borderWidth: 6, }} onPress={handleTakePicture} > <View style={{ opacity: 0.5 }} /> </TouchableOpacity> </View> ); }
2. Android 黑屏问题修复步骤
- 权限配置检查:在
android/app/src/main/AndroidManifest.xml中确认添加相机权限:<uses-permission android:name="android.permission.CAMERA" /> - 依赖与缓存清理:
- 执行
./gradlew clean清理 Android 构建缓存 - 确认
react-native-vision-camera和react-native-vision-camera-face-detector版本与当前 React Native 版本兼容
- 执行
- Frame Processor 配置:
在android/app/build.gradle的defaultConfig中添加以下配置,确保帧处理器正常工作:android { defaultConfig { // ... externalNativeBuild { cmake { arguments "-DREACT_NATIVE_FRAME_PROCESSOR=ON" } } } } - 激活相机预览:确保
Camera组件的isActive属性设置为true,这是激活预览的关键 - 样式排查:部分 Android 设备对
overflow: hidden配合圆角的渲染存在兼容性问题,可临时移除圆角样式测试是否解决黑屏 - 像素格式适配:若上述步骤无效,尝试在
Camera组件中添加pixelFormat="yuv"参数,适配部分设备的相机预览格式
内容的提问来源于stack exchange,提问作者stylx
相关产品推荐
相关产品推荐

