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

如何使用Expo实现图片保存至本地设备

Expo环境下拍照并保存图片到本地实现方案

Expo 不再兼容 React Native 原生的 CameraRoll 组件,不需要 eject 原生工程,使用Expo官方维护的配套库即可完成需求,全程兼容Expo Go调试环境、开发构建与正式生产包。

依赖安装

执行以下命令安装所需官方库,不要使用第三方未做Expo适配的相机/相册类库,避免出现原生依赖不兼容问题:

npx expo install expo-camera expo-media-library
  • expo-camera:官方提供的相机组件,支持拍照、录屏、参数调节等能力
  • expo-media-library:官方提供的系统媒体库访问组件,替代原生CameraRoll实现图片/视频保存到本地相册、读取媒体资源等能力

权限配置

在项目根目录的app.json中补充对应端的权限声明,否则应用会在调用相关能力时崩溃:

{
  "expo": {
    "ios": {
      "infoPlist": {
        "NSCameraUsageDescription": "应用需要访问相机以拍摄照片",
        "NSPhotoLibraryAddUsageDescription": "应用需要访问相册以保存拍摄的照片"
      }
    },
    "android": {
      "permissions": ["CAMERA", "WRITE_EXTERNAL_STORAGE", "READ_MEDIA_IMAGES"]
    }
  }
}

配置说明:iOS端必须在infoPlist中写清权限用途,否则上架会被拒;Android端READ_MEDIA_IMAGES为Android13及以上版本读取媒体所需权限,WRITE_EXTERNAL_STORAGE仅Android12及以下版本需要,Expo会根据系统版本自动适配权限申请逻辑。

核心实现代码

import { useState, useRef } from 'react';
import { View, Button, Image, Text } from 'react-native';
import { Camera, CameraType } from 'expo-camera';
import * as MediaLibrary from 'expo-media-library';

export default function CameraCapture() {
  const [permissionGranted, setPermissionGranted] = useState(null);
  const [lastPhotoUri, setLastPhotoUri] = useState(null);
  const cameraRef = useRef(null);

  // 页面初始化时申请相机、相册写入权限
  useState(() => {
    (async () => {
      const cameraRes = await Camera.requestCameraPermissionsAsync();
      const mediaRes = await MediaLibrary.requestPermissionsAsync();
      setPermissionGranted(cameraRes.status === 'granted' && mediaRes.status === 'granted');
    })();
  }, []);

  // 拍照并保存到本地相册
  const handleTakeAndSave = async () => {
    if (!cameraRef.current) return;
    // 拍摄照片,quality取值0-1,数值越高画质越好、文件体积越大
    const photoRes = await cameraRef.current.takePictureAsync({
      quality: 0.8,
      skipProcessing: false
    });
    setLastPhotoUri(photoRes.uri);
    // 调用媒体库接口将图片写入系统公共相册
    await MediaLibrary.saveToLibraryAsync(photoRes.uri);
    alert('图片已成功保存至设备本地相册');
  };

  if (permissionGranted === null) return <View><Text>权限加载中...</Text></View>;
  if (!permissionGranted) return <View><Text>未获得相机/相册权限,请在系统设置中开启后重试</Text></View>;

  return (
    <View style={{ flex: 1 }}>
      <Camera
        style={{ flex: 1 }}
        type={CameraType.back}
        ref={cameraRef}
      >
        <View style={{ position: 'absolute', bottom: 60, width: '100%', alignItems: 'center' }}>
          <Button title="拍照并保存到本地" onPress={handleTakeAndSave} />
        </View>
      </Camera>
      {lastPhotoUri && (
        <Image
          source={{ uri: lastPhotoUri }}
          style={{ width: 100, height: 100, position: 'absolute', top: 60, right: 20, borderRadius: 8 }}
        />
      )}
    </View>
  );
}

补充说明

  • 如果不需要自定义相机界面,也可以直接用expo-image-picker调用系统相机拍摄,拿到返回的图片uri后,同样调用MediaLibrary.saveToLibraryAsync(uri)即可完成保存,逻辑完全一致
  • 如果不需要把图片存到系统公共相册,仅存在应用私有目录下供应用自身使用,拍照后直接使用expo-file-system操作文件移动存储即可,不需要申请相册相关权限
  • Android 10及以上版本使用分区存储机制,expo-media-library已经做了适配,不需要额外做存储路径兼容

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 15:15:34