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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 15:13:12