React Native中如何向Firebase Storage上传视频?
解决React Native中Firebase Storage上传视频报错"Expected Blob or File"的问题
你遇到的这个错误核心原因很明确:Firebase Web SDK的put()方法是为浏览器环境设计的,它期待接收Blob或File类型的对象,但React Native里的视频URI只是本地文件的路径字符串,无法直接被识别,所以才会抛出"Invalid argument"的错误。
下面给你两种可行的解决方案,优先推荐第一种,更适配React Native生态:
方案1:使用react-native-firebase的Storage模块(推荐)
react-native-firebase是Firebase官方为React Native打造的适配库,它的Storage模块专门提供了putFile()方法,直接支持本地文件URI,不需要额外做格式转换,是最省心的方案。
实现步骤:
- 如果你还没安装
react-native-firebase,先按照官方指引完成安装和基础配置(重点确保Storage模块配置正确)。 - 修改你的上传函数为以下代码:
import storage from '@react-native-firebase/storage'; async function uploadVideo(uri) { console.log("inside"); // 创建Storage存储引用 const videoRef = storage().ref('images').child(`${Student.FirstName}`).child('video_098'); try { // 直接传入视频URI启动上传任务 const uploadTask = videoRef.putFile(uri, { contentType: 'video/mp4', }); // 监听上传进度与状态变化 uploadTask.on('state_changed', snapshot => { const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; console.log(`Upload is ${progress}% done`); switch (snapshot.state) { case storage.TaskState.PAUSED: console.log('Upload is paused'); break; case storage.TaskState.RUNNING: console.log('Upload is running'); break; } }); // 等待上传完成,获取下载链接 await uploadTask; const downloadURL = await videoRef.getDownloadURL(); console.log('File available at', downloadURL); } catch (error) { console.error('Upload failed:', error); // 根据错误码处理不同场景 switch (error.code) { case 'storage/unauthorized': alert('没有权限访问存储资源'); break; case 'storage/canceled': console.log('用户取消了上传'); break; default: alert('上传出错,请重试'); break; } } }
这个方案的优势是完全适配RN环境,不需要手动处理文件读取和格式转换,代码简洁且可靠性更高。
方案2:用rn-fetch-blob将本地文件转为Blob(适配Web SDK)
如果你不想切换SDK,坚持使用Firebase Web SDK,可以通过rn-fetch-blob读取本地文件并转换为Blob对象,再传给put()方法。
实现步骤:
- 先安装依赖:
npm install rn-fetch-blob --save # 或者使用yarn yarn add rn-fetch-blob
- 修改你的上传函数:
import RNFetchBlob from 'rn-fetch-blob'; import firebase from 'firebase/app'; import 'firebase/storage'; import { Platform } from 'react-native'; function uploadVideo(uri) { console.log("inside"); const uploadUri = Platform.OS === 'ios' ? uri.replace('file://', '') : uri; const videoRef = firebase.storage().ref('images').child(`${Student.FirstName}`).child('video_098'); // 读取本地文件为base64格式,再转换为Blob RNFetchBlob.fs.readFile(uploadUri, 'base64') .then(base64Data => { // 构建Blob对象 const blob = RNFetchBlob.polyfill.Blob.build(base64Data, { type: 'video/mp4' }); // 替换RN环境的Blob实现(RN原生没有浏览器的Blob对象) window.Blob = RNFetchBlob.polyfill.Blob; const metadata = { contentType: 'video/mp4' }; const uploadTask = videoRef.put(blob, metadata); // 监听上传状态(和你原来的逻辑一致) uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED, snapshot => { const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; console.log(`Upload is ${progress}% done`); switch (snapshot.state) { case firebase.storage.TaskState.PAUSED: console.log('Upload is paused'); break; case firebase.storage.TaskState.RUNNING: console.log('Upload is running'); break; } }, error => { console.error('Upload error:', error); switch (error.code) { case 'storage/unauthorized': // 处理权限问题 break; case 'storage/canceled': // 处理取消上传 break; case 'storage/unknown': // 未知错误,可查看error.serverResponse详情 break; } }, () => { // 上传完成,获取下载链接 uploadTask.snapshot.ref.getDownloadURL().then(downloadURL => { console.log('File available at', downloadURL); // 记得关闭Blob释放资源 blob.close(); }); } ); }) .catch(err => { console.error('Failed to read local file:', err); }); }
这种方法需要手动处理Blob的创建和环境polyfill,适合坚持使用Web SDK的场景,但相对方案1会繁琐一些。
内容的提问来源于stack exchange,提问作者Shivam
相关产品推荐
相关产品推荐

