You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从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" />
    
  • 依赖与缓存清理:
    1. 执行 ./gradlew clean 清理 Android 构建缓存
    2. 确认 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 15:21:02