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

React Native iOS端RNCamera扫码相机无法打开,显示黑屏求助

React Native iOS 相机扫描QR码黑屏问题

我在React Native开发iOS应用时,调用相机扫描QR码出现黑屏。已完成相机权限申请逻辑,Info.plist中配置了NSCameraUsageDescription,日志显示权限已授予且成功获取到QR字符串,但无任何报错或警告,相机仅显示空白黑屏。

我的代码

import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { RNCamera } from 'react-native-camera';
import { request, PERMISSIONS, check, RESULTS } from 'react-native-permissions';
import axios from 'axios';
import Toast from 'react-native-simple-toast';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { API_DOMAIN, GET_EVENT_DETAILS } from '../../components/apiConstants';

const CheckedIn = ({ navigation, route }) => {
  const [isCheckedIn, setIsCheckedIn] = useState(false);
  const [checkInMessage, setCheckInMessage] = useState('');
  const [eQRstring, setEQRstring] = useState('');

  useEffect(() => {
    fetchQRString();
  }, []);

  const fetchQRString = async () => {
    try {
      const storedEvent = await AsyncStorage.getItem('selectedSeminar');
      const selectedSeminar = JSON.parse(storedEvent);
      const eventID = selectedSeminar.eid;
      const pocid = await AsyncStorage.getItem('pocid');

      const response = await axios.get(
        `${API_DOMAIN}${GET_EVENT_DETAILS}?eid=${eventID}&poid=${pocid}`
      );

      console.log(response.data.data.eQRstring);
      if (response.data.data.eQRstring) {
        const qrString = response.data.data.eQRstring;
        setEQRstring(qrString);
        console.log('QR String:', qrString);
      } else {
        console.error('eQRstring is undefined in the response data');
      }
    } catch (error) {
      console.error('Error fetching QR string:', error);
    }
  };

  const handleScanSuccess = async (event) => {
    try {
      const scannedStringData = event.data.trim();
      console.log('Scanned Data:', scannedStringData);
      console.log('Expected QR String:', eQRstring);

      if (scannedStringData === eQRstring) {
        Toast.show('Check-in Successful!', Toast.SHORT);
        navigation.navigate('HomeScreen');
      } else {
        setCheckInMessage('Invalid QR code');
        console.log('Invalid QR code');
        Toast.show('Invalid QR code!', Toast.SHORT);
        navigation.navigate('HomeScreen');
      }
    } catch (error) {
      setCheckInMessage('Error handling scan');
      console.error('Error handling scan:', error);
    }
  };

  const requestCameraPermission = async () => {
    const result = await check(PERMISSIONS.IOS.CAMERA);

    if(result === RESULTS.GRANTED){
      console.log('Camera permission granted');
    }
    else{
      const permissionResult = await request(PERMISSIONS.IOS.CAMERA);
      if (permissionResult !== 'granted') {
        console.error('Camera permission denied');
      }
      else{
        console.log('Camera permissions granted');
      }
    }
  };

  useEffect(() => {
    requestCameraPermission();
  }, []);

  const renderQRCodeScanner = () => {
    console.log('Rendering QR Code Scanner');
    return (
      <RNCamera
        style={styles.cameraStyle}
        onRead={handleScanSuccess}
        onCameraReady={()=> console.log('Camera is ready')}
        showMarker={true}
        markerStyle={styles.markerStyle}
        captureAudio={false}
        ratio='16:9'
      />
    );
  };

  return (
    <View style={styles.container}>
      {isCheckedIn ? (
        <Text style={styles.text}>Checked In!</Text>
      ) : (
        <>
          {renderQRCodeScanner()}
          {checkInMessage ? (
            <Text style={styles.message}>{checkInMessage}</Text>
          ) : null}
        </>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  cameraStyle: {
    flex: 1,
    borderWidth: 1,
    backgroundColor: 'red',
    justifyContent: 'center',
    alignItems: 'center',
  },
  markerStyle: {
    borderColor: 'red',
    borderRadius: 10,
  },
  text: {
    fontSize: 24,
    fontWeight: 'bold',
    color: 'green',
  },
  message: {
    fontSize: 16,
    color: 'red',
    marginTop: 20,
  },
});

export default CheckedIn;

Info.plist权限配置

<key>NSCameraUsageDescription</key>
<string>We need access to your camera to scan QR codes.</string>

日志信息

  • LOG QR String: 1688236200
  • LOG Camera permission granted

排查与解决方法

1. 修复相机视图样式

当前cameraStyle的backgroundColor: 'red'会覆盖相机画面,且布局设置不合理。修改样式确保相机占满屏幕:

const styles = StyleSheet.create({
  container: {
    flex: 1,
    // 移除justifyContent和alignItems,让相机视图自然填充
  },
  cameraStyle: {
    flex: 1,
    width: '100%',
    height: '100%',
    // 移除backgroundColor和无关布局属性
  },
  // 其他样式保持不变
});

2. 确保权限生效后再渲染相机

现在两个useEffect并行执行,可能出现相机先渲染但权限未完全生效的情况。添加状态控制相机渲染时机:

const [cameraPermissionGranted, setCameraPermissionGranted] = useState(false);

// 修改权限请求函数
const requestCameraPermission = async () => {
  const result = await check(PERMISSIONS.IOS.CAMERA);
  if(result === RESULTS.GRANTED){
    console.log('Camera permission granted');
    setCameraPermissionGranted(true);
  } else {
    const permissionResult = await request(PERMISSIONS.IOS.CAMERA);
    if (permissionResult === RESULTS.GRANTED) {
      console.log('Camera permissions granted');
      setCameraPermissionGranted(true);
    } else {
      console.error('Camera permission denied');
    }
  }
};

// 修改相机渲染函数
const renderQRCodeScanner = () => {
  if(!cameraPermissionGranted) return null;
  console.log('Rendering QR Code Scanner');
  return (
    <RNCamera
      style={styles.cameraStyle}
      onRead={handleScanSuccess}
      onCameraReady={()=> console.log('Camera is ready')}
      showMarker={true}
      markerStyle={styles.markerStyle}
      captureAudio={false}
      ratio='16:9'
    />
  );
};

3. 验证依赖兼容性与项目配置

  • 确保react-native-camera版本与当前React Native版本兼容,执行更新命令:
    npm install react-native-camera@latest --save
    cd ios && pod install && cd ..
    
  • 打开Xcode,清理编译缓存(Product > Clean Build Folder)后重新编译项目。
  • 确认Info.plist中NSCameraUsageDescription配置无误,字符串不为空。

4. 改用真机测试

iOS模拟器的相机功能有限,黑屏问题大概率在真机上会消失,直接使用真机进行测试验证。


内容的提问来源于stack exchange,提问作者Aashi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 13:07:09