Expo Camera iOS端调用createAssetAsync保存.mov视频失败求助
Expo React Native iOS端视频录制保存失败问题解决建议
问题说明
在React Native + Expo开发中,实现相机录制视频并保存到手机的功能,Android端运行正常,但iOS端调用MediaLibrary.createAssetAsync时失败,报错如下:
Error: This URL does not contain a valid asset type: file:///var/mobile/Containers/Data/Application/22FC2F8C-E052-4FF5-B451-4973C95AD74E/Library/Caches/Camera/50220C17-AB3B-4586-80D7-67A6D27D6105.mov
{"code": "ERR_UNSUPPORTED_ASSET_TYPE"}
相关代码
保存视频的useEffect代码
useEffect(() => { const saveVideo = async () => { console.log('rURI:', recordedUri); console.log('recordedUri type:', typeof recordedUri); if (recordedUri) { // Check file existence const fileInfo = await FileSystem.getInfoAsync(recordedUri); console.log('fileInfo:', fileInfo); if (!fileInfo.exists) { console.error('File does not exist:', recordedUri); return; } const { status, canAskAgain } = await MediaLibrary.requestPermissionsAsync(); if (status !== 'granted' && canAskAgain) { const fullPermission = await MediaLibrary.requestPermissionsAsync({ writeOnly: false }); console.log('Full permission status:', fullPermission.status); } try { const asset = await MediaLibrary.createAssetAsync(recordedUri); console.log('asset:', asset); setNewAssetCounter(newAssetCounter + 1); } catch (err) { console.log('Error creating asset:', JSON.stringify(err, null, 2)) } } closeCamera(); } saveVideo(); }, [recordedUri])
录制视频的代码
const startRecording = async () => { if (cameraRef.current) { setVideoElapsedTime(0); const videoRecordPromise = cameraRef.current.recordAsync(); if (videoRecordPromise) { setIsRecording(true); timerRef.current = setInterval(() => { setVideoElapsedTime((prevTime) => prevTime + 1); }, 1000); const video = await videoRecordPromise; setRecordedUri(video.uri); } } }; // Stop recording const stopRecording = async () => { const { status } = await MediaLibrary.requestPermissionsAsync(); console.log('status:', status); if (status !== 'granted') { alert('Permission to access media library is required!'); return; } console.log('line157'); try { if (cameraRef.current && isRecording) { console.log('line159'); cameraRef.current.stopRecording(); setIsRecording(false); clearInterval(timerRef.current); console.log('line162'); } } catch (error) { console.error('Error saving video:', error); } };
解决建议
1. 将视频复制到可识别目录再保存
iOS系统中,Caches目录下的文件可能不被MediaLibrary.createAssetAsync识别,建议先将视频复制到Document目录再执行保存:
const saveVideo = async () => { if (recordedUri) { const fileInfo = await FileSystem.getInfoAsync(recordedUri); if (!fileInfo.exists) { console.error('File does not exist:', recordedUri); return; } // 生成唯一文件名并复制到Document目录 const uniqueFileName = `${Date.now()}.mov`; const targetUri = `${FileSystem.documentDirectory}${uniqueFileName}`; await FileSystem.copyAsync({ from: recordedUri, to: targetUri }); // 确认权限 const { status } = await MediaLibrary.requestPermissionsAsync(); if (status !== 'granted') { alert('需要授予媒体库权限才能保存视频'); return; } try { const asset = await MediaLibrary.createAssetAsync(targetUri); console.log('asset:', asset); setNewAssetCounter(prev => prev + 1); // 可选:删除临时文件 await FileSystem.deleteAsync(targetUri); } catch (err) { console.log('Error creating asset:', JSON.stringify(err, null, 2)) } } closeCamera(); };
2. 直接使用相机的saveToCameraRoll选项
Expo相机的recordAsync方法支持直接将录制视频保存到相册,无需手动调用createAssetAsync,简化代码:
const startRecording = async () => { if (cameraRef.current) { setVideoElapsedTime(0); setIsRecording(true); timerRef.current = setInterval(() => { setVideoElapsedTime((prevTime) => prevTime + 1); }, 1000); // 录制并直接保存到相册 const video = await cameraRef.current.recordAsync({ saveToCameraRoll: true }); setRecordedUri(video.uri); setIsRecording(false); clearInterval(timerRef.current); } };
3. 完善iOS权限配置
在app.json中添加必要的权限描述,确保iOS系统允许访问相机和相册:
{ "expo": { "ios": { "infoPlist": { "NSCameraUsageDescription": "需要相机权限进行视频录制", "NSPhotoLibraryAddUsageDescription": "需要访问相册权限保存录制的视频", "NSPhotoLibraryUsageDescription": "需要访问相册权限保存录制的视频" } } } }
4. 升级Expo SDK版本
部分旧版本Expo SDK存在iOS视频URI处理的bug,尝试升级到最新稳定版,修复潜在兼容性问题。
内容的提问来源于stack exchange,提问作者Anand
相关产品推荐
相关产品推荐

