Expo Media Library保存大文件到Android图库异常及替代方案咨询
解决方案
问题根因
你遇到的大文件导出卡住问题是Expo MediaLibrary封装层的已知缺陷:saveToLibraryAsync和createAssetAsync默认会将整个源文件一次性加载到内存再写入公共存储,4-5分钟的720P视频大小通常在400M以上,超出安卓应用默认内存分配阈值就会触发IO异常,小文件因为内存占用低不会触发问题。
可用方案
方案1:使用expo-file-system直接写入公共媒体目录(适配Managed工作流,无需修改原生代码)
该方案避开MediaLibrary的封装层,直接通过系统文件接口分块写入,无内存溢出问题,步骤如下:
- 权限申请
- 安卓13及以上:申请
READ_MEDIA_VIDEO、WRITE_MEDIA_VIDEO权限 - 安卓12及以下:申请
WRITE_EXTERNAL_STORAGE权限
- 安卓13及以上:申请
- 代码实现示例:
import * as FileSystem from 'expo-file-system'; import * as Permissions from 'expo-permissions'; // 先申请存储权限 const { status } = await Permissions.askAsync(Permissions.MEDIA_LIBRARY); if (status !== 'granted') return; // 源文件路径:你的FFmpeg拼接完成的视频本地URI,格式为file://开头的私有目录路径 const sourceVideoUri = '你的拼接视频本地路径'; const fileName = `merge_video_${Date.now()}.mp4`; // 安卓公共视频目录目标URI const destVideoUri = `${FileSystem.externalStorageDirectory}DCIM/Camera/${fileName}`; // 分块拷贝文件,不会全量加载到内存 await FileSystem.copyAsync({ from: sourceVideoUri, to: destVideoUri }); // 通知系统媒体库刷新,让视频在图库中可见 await FileSystem.scanFolderAsync(destVideoUri);
方案2:拆分MediaLibrary操作逻辑(保留MediaLibrary依赖,改动最小)
MediaLibrary卡顿的核心是跨目录拷贝大文件,你可以先将拼接完成的视频从应用私有目录移动到外部公共缓存目录,再调用MediaLibrary的接口仅做索引注册,无需触发大文件拷贝:
import * as FileSystem from 'expo-file-system'; import * as MediaLibrary from 'expo-media-library'; // 权限申请逻辑同上 const sourceVideoUri = '你的拼接视频本地路径'; const tempExternalUri = `${FileSystem.externalCacheDirectory}temp_merge.mp4`; // 先移动文件到外部缓存 await FileSystem.moveAsync({ from: sourceVideoUri, to: tempExternalUri }); // 此时调用createAssetAsync仅做索引注册,不会拷贝大文件 const asset = await MediaLibrary.createAssetAsync(tempExternalUri); // 可选:移动到指定相册 const album = await MediaLibrary.getAlbumAsync('你的应用相册名'); if (album) await MediaLibrary.addAssetsToAlbumAsync([asset], album);
方案3:原生MediaStore API写入(适配Bare工作流,性能最优)
如果是Bare工作流可以直接调用安卓原生MediaStore接口分块写入,完全避开Expo封装的问题:
- 向
MediaStore.Video.Media.EXTERNAL_CONTENT_URI插入一条新的视频记录,标记IS_PENDING=1 - 获取该记录的输出流,将本地视频文件按1M/块的粒度分片写入输出流
- 写入完成后更新
IS_PENDING=0,系统会自动刷新图库显示
避坑提示
- 大文件操作建议放在后台任务中执行,避免应用切后台后被系统杀死导致写入失败
- 目标文件名建议添加时间戳后缀,避免重复覆盖
- 安卓14以上无需申请存储写入权限,仅需要媒体库访问权限即可写入公共视频目录
内容的提问来源于stack exchange,提问作者Asp1re
相关产品推荐
相关产品推荐

