如何在Expo应用中下载音视频文件并仅在应用内可见?
Expo 音视频离线下载(仅应用内可见)实现方案
要实现仅应用内可见的音视频离线下载,核心是把文件存储到应用私有沙盒目录,避开系统媒体扫描范围,以下是具体步骤和代码:
1. 核心原理
Expo 的 expo-file-system 提供了应用专属的私有目录:
FileSystem.documentDirectory:长期存储目录,文件不会被系统自动清理,且系统媒体库/文件管理器无访问权限- 给文件名加上前缀点(.):即使目录被意外访问,系统也会将其识别为隐藏文件,默认不显示
2. 下载文件到私有目录
使用 FileSystem.downloadAsync 将音视频直接保存到私有目录,全程不接触系统媒体库:
import * as FileSystem from 'expo-file-system'; /** * 下载音视频到应用私有目录 * @param {string} mediaUrl - 音视频远程地址 * @param {string} filename - 自定义文件名(如 "lesson-1.mp4") * @returns {string} 本地文件URI */ const downloadPrivateMedia = async (mediaUrl, filename) => { // 构造私有路径:隐藏文件名 + 私有目录 const privateFilePath = `${FileSystem.documentDirectory}.${filename}`; // 检查文件是否已存在,避免重复下载 const fileExists = await FileSystem.getInfoAsync(privateFilePath).then(info => info.exists); if (fileExists) { return privateFilePath; } // 执行下载 const downloadResult = await FileSystem.downloadAsync(mediaUrl, privateFilePath); if (downloadResult.status !== 200) { throw new Error(`下载失败:状态码 ${downloadResult.status}`); } return downloadResult.uri; };
3. 离线播放私有文件
使用 Expo expo-av 模块直接读取私有目录的文件,无需额外转换:
import { Video } from 'expo-av'; import { useState } from 'react'; import { Button, View } from 'react-native'; export default function OfflinePlayer() { const [localVideoUri, setLocalVideoUri] = useState(null); const handleDownload = async () => { try { const uri = await downloadPrivateMedia( 'https://your-media-server.com/video.mp4', 'math-lesson-01.mp4' ); setLocalVideoUri(uri); } catch (err) { alert(err.message); } }; return ( <View style={{ flex: 1, padding: 20 }}> <Button title="下载视频" onPress={handleDownload} /> {localVideoUri && ( <Video source={{ uri: localVideoUri }} style={{ flex: 1, marginTop: 20 }} useNativeControls resizeMode="contain" /> )} </View> ); }
4. 关键注意事项
- 禁用媒体库API:绝对不要调用
expo-media-library的createAssetAsync等方法,否则会将文件同步到系统相册/文件管理器 - 目录选择:用
documentDirectory而非cacheDirectory,后者可能被系统在低存储空间时自动清理 - 权限:无需申请媒体库访问权限,仅需基础网络权限(Expo 默认已配置)
- 文件管理:可通过
FileSystem.readDirectoryAsync(FileSystem.documentDirectory)列出所有下载的文件,用FileSystem.deleteAsync(path)删除不需要的文件
内容的提问来源于stack exchange,提问作者Komal Parulekar
相关产品推荐
相关产品推荐

