如何使用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
相关产品推荐
相关产品推荐

