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

Expo中使用react-native-camera遇Possible Unhandled Promise Rejection错误求助

问题

在Expo中使用react-native-camera时出现错误:Possible Unhandled Promise Rejection (id: 0),代码如下:

import {StatusBar} from 'expo-status-bar';
import React from "react";
import { StyleSheet, Modal, View, Pressable, Text, SafeAreaView, Button, Image, 
PushNotificationIOS } from "react-native";
import { useEffect, useRef, useState } from 'react';
import Icon from "react-native-vector-icons/MaterialIcons";
import {shareAsync} from 'expo-sharing';
import * as MediaLibrary from 'expo-media-library';
import { Camera } from 'expo-camera';


export default function App() {

  let cameraRef = useRef();
  const [hasCameraPermission, setHasCameraPermission] = useState();
  const [hasMediaLibraryPermission, setHasMediaLibraryPermission] = useState();
  const [photo, setPhoto]  = useState();

  useEffect(()=>{
    (async ()=>{
      const cameraPermission = await Camera.requestCameraPermissionsAsync();
      constMediaLibraryPermission = await MediaLibrary.requestMediaLibraryPermissionsAsync();
      setHasCameraPermission(cameraPermission.status === "granted");
      setHasMediaLibraryPermission(MediaLibraryPermission.status === "granted");

    })();
  },[]);

  if (hasCameraPermission === undefined){
    return <Text> Requesting permissions...</Text>
  } else if (!hasCameraPermission){
    return <Text> Permission for camera not granted. Please change this in settinr.</Text>
  }

  let takePic = async () => {
    let options = {
      quality :1,
      base64: true,
      exif : false
    };

    let newPhoto = await cameraRef.current.takePictureAsync(options);
    setPhoto(newPhoto);
  };

  if(photo){
    let sharePic = () => {
      shareAsync(photo.uri).then(() => {
        setPhoto(undefined);
      });

    };
    let savePhoto = () => {
      MediaLibrary.saveToLibraryAsync(photo.uri).then(() =>{
        setPhoto(undefined);
      });

    };

    return (
      <SafeAreaView style = {styles.container}>
        <Image style = {styles.preview} source = {{uri: "data:image/jpg;base64," + 
photo.base64}}/>
        <Button title = "share" onPress = {sharePic}/>
        {hasMediaLibraryPermission ? <Button title = "save" onPress = {savePhoto}/>:undefined}
         <Button title = "Discard" onPress = {()=> setPhoto(undefined)}/>
      </SafeAreaView>
    )
  }

  return (
<Camera style={styles.container} ref = {cameraRef}>
  <View style = {styles.buttonContainer}>
    <Button title = "Takc Pic" onPress = {takePic} />
  </View>
  <StatusBar style="auto" />
</Camera>
  );

}


const styles = StyleSheet.create({
  container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
  },
   buttonContainer:{
    backgroundColor :'#fff',
    alignSelf:'flex-end'
  },
  preview:{
    alignSelf:'stretch',
    flex:1
  }
});
解决方案

错误核心原因

  1. 变量拼写错误:constMediaLibraryPermission 缺少空格,应为const mediaLibraryPermission,后续引用时误写为MediaLibraryPermission,导致未定义变量触发Promise拒绝。
  2. 异步操作无错误捕获:takePictureAsync、shareAsync、saveToLibraryAsync这些异步方法可能抛出异常,未做处理会导致未捕获的Promise拒绝。
  3. 权限状态边界模糊:初始状态hasCameraPermission为undefined,需确保权限请求完成后再渲染相机组件。

修复后的完整代码

import { StatusBar } from 'expo-status-bar';
import React from "react";
import { StyleSheet, Text, SafeAreaView, Button, Image } from "react-native";
import { useEffect, useRef, useState } from 'react';
import { shareAsync } from 'expo-sharing';
import * as MediaLibrary from 'expo-media-library';
import { Camera } from 'expo-camera';


export default function App() {
  const cameraRef = useRef();
  const [hasCameraPermission, setHasCameraPermission] = useState(null);
  const [hasMediaLibraryPermission, setHasMediaLibraryPermission] = useState(null);
  const [photo, setPhoto] = useState(null);
  const [errorMsg, setErrorMsg] = useState('');

  useEffect(() => {
    const requestPermissions = async () => {
      try {
        const cameraPermission = await Camera.requestCameraPermissionsAsync();
        const mediaLibraryPermission = await MediaLibrary.requestMediaLibraryPermissionsAsync();
        
        setHasCameraPermission(cameraPermission.status === "granted");
        setHasMediaLibraryPermission(mediaLibraryPermission.status === "granted");
      } catch (err) {
        setErrorMsg('权限请求失败:' + err.message);
      }
    };
    requestPermissions();
  }, []);

  if (errorMsg) {
    return <Text style={{ padding: 20 }}>{errorMsg}</Text>;
  }

  if (hasCameraPermission === null) {
    return <Text style={{ padding: 20 }}>请求权限中...</Text>;
  } else if (!hasCameraPermission) {
    return <Text style={{ padding: 20 }}>相机权限未授予,请在设置中修改。</Text>;
  }

  const takePic = async () => {
    try {
      if (!cameraRef.current) return;
      
      const options = {
        quality: 1,
        base64: true,
        exif: false
      };

      const newPhoto = await cameraRef.current.takePictureAsync(options);
      setPhoto(newPhoto);
    } catch (err) {
      setErrorMsg('拍照失败:' + err.message);
    }
  };

  if (photo) {
    const sharePic = async () => {
      try {
        await shareAsync(photo.uri);
        setPhoto(null);
      } catch (err) {
        setErrorMsg('分享失败:' + err.message);
      }
    };

    const savePhoto = async () => {
      try {
        await MediaLibrary.saveToLibraryAsync(photo.uri);
        setPhoto(null);
      } catch (err) {
        setErrorMsg('保存失败:' + err.message);
      }
    };

    return (
      <SafeAreaView style={styles.container}>
        {errorMsg ? <Text style={{ color: 'red', padding: 10 }}>{errorMsg}</Text> : null}
        <Image style={styles.preview} source={{ uri: "data:image/jpg;base64," + photo.base64 }} />
        <Button title="分享" onPress={sharePic} />
        {hasMediaLibraryPermission ? <Button title="保存" onPress={savePhoto} /> : null}
        <Button title="取消" onPress={() => setPhoto(null)} />
      </SafeAreaView>
    );
  }

  return (
    <Camera style={styles.container} ref={cameraRef}>
      {errorMsg ? <Text style={{ color: 'red', padding: 10, backgroundColor: 'white' }}>{errorMsg}</Text> : null}
      <View style={styles.buttonContainer}>
        <Button title="拍照" onPress={takePic} />
      </View>
      <StatusBar style="auto" />
    </Camera>
  );
}


const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  buttonContainer: {
    backgroundColor: '#fff',
    alignSelf: 'flex-end',
    padding: 10,
  },
  preview: {
    alignSelf: 'stretch',
    flex: 1,
  }
});

内容的提问来源于stack exchange,提问作者이소민

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 22:48:17