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

React Native中expo-av缓存视频无法播放的问题求助

Expo AV 本地缓存视频无法播放问题排查与解决

问题场景

在裸React Native项目中集成expo-av后,尝试用react-native-fs缓存视频并播放本地文件,已获取到合法的本地路径(如/Users/jamess/Library/Developer/CoreSimulator/.../Documents/video5_g243f4.mp4),但expo-av的Video组件无法播放该缓存视频,而react-native-video可正常运行。相关实现代码如下:

const App = (props: Props) => {
    const [video, setVideo] = useState('');

    useEffect(() => {
        downloadVideo(props.video);
    }, []);

    const downloadVideo = async (videoUrl) => {
        const filename = videoUrl.substring(videoUrl.lastIndexOf('/') + 1);
        const cachePath = RNFS.DocumentDirectoryPath
        const exists = await RNFS.exists(cachePath + filename);
        if (!exists) {
            const data = await fetch(videoUrl);
            const blob = await data.blob();
            await RNFS.writeFile(cachePath + filename, blob);
        }
        console.log(`${cachePath}/${filename}`)
        setVideo(`${cachePath}/${filename}`)
    };


    console.log(props.video)
    return (
        <View>
            <Video
               source={{uri: video}}
                resizeMode="cover"
                repeat
                shouldPlay
                isMuted={false}
                style={styles.backgroundVideo}
            />
        </View>
    );
}

export default App;

问题原因

  • 文件写入逻辑错误:RNFS的writeFile方法默认仅支持字符串或base64编码数据,直接传入fetch获取的Blob对象会导致文件内容损坏。react-native-video可能对这类损坏文件有兼容处理,但expo-av的解码器要求文件必须完全符合格式规范。
  • 路径拼接隐患:代码中cachePath + filename的写法可能出现路径分隔符缺失(比如DocumentDirectoryPath结尾无/时,拼接后会变成/xxxDocumentsvideo.mp4),导致实际写入路径与播放路径不一致。

解决方案

方案1:改用RNFS.downloadFile下载视频(推荐)

直接使用RNFS的原生下载API,避免手动处理Blob,确保文件完整性:

const downloadVideo = async (videoUrl) => {
    const filename = videoUrl.substring(videoUrl.lastIndexOf('/') + 1);
    const cachePath = `${RNFS.DocumentDirectoryPath}/${filename}`;
    const exists = await RNFS.exists(cachePath);
    
    if (!exists) {
        const downloadResult = await RNFS.downloadFile({
            fromUrl: videoUrl,
            toFile: cachePath
        }).promise;
        
        // 校验下载状态
        if (downloadResult.statusCode !== 200) {
            console.error('视频下载失败');
            return;
        }
    }
    
    setVideo(cachePath);
};

方案2:正确处理Blob写入(不推荐,易出问题)

若必须用fetch获取Blob,需先将其转换为base64编码再写入:

const downloadVideo = async (videoUrl) => {
    const filename = videoUrl.substring(videoUrl.lastIndexOf('/') + 1);
    const cachePath = `${RNFS.DocumentDirectoryPath}/${filename}`;
    const exists = await RNFS.exists(cachePath);
    
    if (!exists) {
        const response = await fetch(videoUrl);
        const blob = await response.blob();
        
        // 将Blob转换为base64
        const base64Data = await new Promise((resolve) => {
            const reader = new FileReader();
            reader.onloadend = () => resolve(reader.result.split(',')[1]);
            reader.readAsDataURL(blob);
        });
        
        await RNFS.writeFile(cachePath, base64Data, 'base64');
    }
    
    setVideo(cachePath);
};

额外检查项

  • 确认styles.backgroundVideo设置了明确的宽高,否则视频可能因尺寸为0而不可见
  • 可在播放前读取文件大小,验证文件是否完整写入:
    const fileInfo = await RNFS.stat(cachePath);
    console.log('文件大小:', fileInfo.size);
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 03:35:20