React Native Expo Image Picker上传图片至Firebase Storage(v9)时iOS端应用崩溃问题
iOS上Expo Image Picker上传Firebase Storage崩溃的解决方案
我之前也碰到过一模一样的问题——Android上上传正常,iOS频繁崩溃,报错就是你提到的NSInvalidArgumentException,本质原因是iOS原生的XMLHttpRequest处理本地file://格式的URI时,容易出现路径解析或权限问题,导致生成的Blob对象无效(甚至是nil),传给Firebase的uploadBytes时就触发了崩溃。
下面给你两个经过验证的解决方案,都是针对iOS环境优化的:
方案1:改用Expo FileSystem读取文件并转Blob上传
Expo的FileSystem API是专门为React Native(尤其是iOS)优化的,对本地文件的处理比原生XHR可靠得多。步骤如下:
- 先安装依赖(如果没装的话):
npx expo install expo-file-system
- 修改上传函数:
import { storage } from '../firebase'; import * as FileSystem from 'expo-file-system'; async function uploadImageAsync(uri, name) { // 先校验文件名,避免传入nil导致路径异常 if (!name?.trim()) { throw new Error('文件名不能为空'); } // 检查文件是否存在(可选,但有助于排查问题) const fileInfo = await FileSystem.getInfoAsync(uri); if (!fileInfo.exists) { throw new Error('指定的图片文件不存在'); } // 读取文件为Base64格式 const base64Str = await FileSystem.readAsStringAsync(uri, { encoding: FileSystem.EncodingType.Base64, }); // 将Base64转为Blob const blob = new Blob( [Uint8Array.from(atob(base64Str), char => char.charCodeAt(0))], { type: 'image/jpeg' } // 根据实际图片类型调整,比如png就改成image/png ); const fileRef = ref(storage, `files/${name}`); const result = await uploadBytes(fileRef, blob); // 释放Blob资源 blob.close(); return await getDownloadURL(fileRef); }
方案2:直接上传Base64字符串(更简洁)
Firebase Storage支持直接上传Base64字符串,省去Blob转换的步骤,代码更简洁,也避免了Blob相关的兼容性问题:
import { storage } from '../firebase'; import * as FileSystem from 'expo-file-system'; async function uploadImageAsync(uri, name) { if (!name?.trim()) { throw new Error('文件名不能为空'); } const base64Str = await FileSystem.readAsStringAsync(uri, { encoding: FileSystem.EncodingType.Base64, }); const fileRef = ref(storage, `files/${name}`); // 直接上传Base64,指定内容类型 await uploadString(fileRef, base64Str, 'base64', { contentType: 'image/jpeg', // 匹配你的图片类型 }); return await getDownloadURL(fileRef); }
额外排查点
- 确认Image Picker返回的URI在iOS上是有效的:可以用
FileSystem.getInfoAsync打印文件信息,确保文件存在且有读取权限。 - 检查Firebase Storage的安全规则:虽然Android正常,但也要确保规则允许当前用户上传文件(不过规则问题一般会报权限错误,不是崩溃)。
- 避免重复调用
blob.close():如果你的代码里有其他地方操作Blob,确保只在上传完成后关闭一次。
这两个方案我都在多个Expo iOS项目中用过,完全解决了上传崩溃的问题,你可以优先试试方案2,代码更简单,出错概率更低。
内容的提问来源于stack exchange,提问作者maz32
相关产品推荐
相关产品推荐

