React Native使用aws-sdk上传视频至AWS S3失败解决方案
修复方案
核心问题是安卓端从系统图库选择视频时,react-native-image-picker返回的是content://协议的只读URI,react-native-fs无法直接读取这类路径的文件内容,导致读取出的base64为空,后续转ArrayBuffer、上传流程全部异常。图片上传正常是因为组件返回图片时默认会将文件复制到应用缓存目录,返回可直接访问的文件路径。
最小改动修复(无新增依赖)
直接修改UploadResource方法,在读取文件前增加content URI的适配逻辑:识别到安卓端content协议URI时,先将文件复制到应用专属缓存目录,拿到可正常读取的文件路径后再走后续上传流程,修改后的完整代码如下:
import { s3bucket } from '../aws/configration'; import * as env from '../config/environment'; import fs from 'react-native-fs'; import * as mime from 'react-native-mime-types'; import { decode } from './Base64ToArrayBuffer'; import { Platform } from 'react-native'; export async function UploadResource(file){ return new Promise(async (resolve, reject) => { let tempFilePath = null; try { let accessUri = file.uri; // 适配安卓content://类型只读URI if (Platform.OS === 'android' && accessUri.startsWith('content://')) { const fileExt = mime.extension(file.type) || 'mp4'; tempFilePath = `${fs.CachesDirectoryPath}/upload_${Date.now()}.${fileExt}`; await fs.copyFile(accessUri, tempFilePath); accessUri = tempFilePath; } let contentType = mime.lookup(accessUri) || file.type; if (!contentType) contentType = 'video/mp4'; const base64 = await fs.readFile(accessUri, 'base64'); const fileName = file.fileName || `${Date.now()}${Date.now()}`; const contentDeposition = `inline;filename="${fileName}"`; const arrayBuffer = decode(base64); const params = { Bucket: env.Bucket, Key: fileName, Body: arrayBuffer, ContentDisposition: contentDeposition, ContentType: contentType, }; s3bucket.upload(params, async (err, data) => { // 上传结束清理临时文件 if (tempFilePath) await fs.unlink(tempFilePath).catch(() => {}); if (err) { console.log(err); reject(err); } else { resolve(data.Location); } }); } catch (err) { if (tempFilePath) await fs.unlink(tempFilePath).catch(() => {}); console.log('文件处理失败:', err); reject(err); } }) };
可选性能优化
现有逻辑先将文件读为base64再转ArrayBuffer,处理大体积视频时会占用3-4倍于文件大小的内存,极易引发APP闪退。可以直接用react-native-fs原生支持的ArrayBuffer读取能力,跳过base64转码步骤,既省内存又能加快上传速度:
// 替换原有读base64、decode转码的两行代码即可 const arrayBuffer = await fs.readFile(accessUri, 'arraybuffer');
替换后可以移除自定义的base64转ArrayBuffer工具方法,减少冗余代码。
注意事项
- 安卓13及以上版本需要申请
READ_MEDIA_VIDEO权限才能读取图库视频,不要再使用旧版的READ_EXTERNAL_STORAGE权限,否则会出现权限拒绝错误。 - 复制生成的临时缓存文件必须在上传结束(成功/失败)后清理,避免长期占用用户存储空间。
内容的提问来源于stack exchange,提问作者Gourav Goel
相关产品推荐
相关产品推荐

