Expo React Native中Firebase上传图片无法获取正确存储URI问题
问题描述
在Expo React Native项目中实现Firebase Storage图片上传功能时,排查数小时仍存在以下问题:
- 上传完成后无法将图片的可访问URI赋值给自定义的
image变量 - 图片存储结果异常,存储状态参考:

- 变量始终无法获取正确的URI值
现有实现代码
1. 创建用户逻辑
此处将uploadImage()方法的返回值赋值给imageUri,用于写入Firestore的image字段:
const createUser = async () => { const imageUri = uploadImage() await addDoc( usersCollectionRef, { name: name || null, cep: cep || null, logradouro: logradouro || null, numero: numero || null, bairro: bairro || null, uf: uf || null, image: imageUri || null, }, navigation.navigate("HomeScreen") ); };
2. 图片选择与上传逻辑
调用ImagePicker选择图片、上传至Firebase Storage,逻辑参考官方文档编写:
const pickImage = async () => { let result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.All, allowsEditing: true, aspect: [4, 3], quality: 1, }); console.log(result); if (!result.cancelled) { setImage(result); } }; const uploadImage = () => { const storageRef = ref(storage, `images/${image.name}`); uploadBytes(storageRef, image).then((snapshot) => { console.log(snapshot); }); };
问题根因
代码存在3个核心错误,直接导致上传异常和无法获取正确URI:
- 异步逻辑未等待:
uploadImage是异步操作,但方法既没有声明async、返回Promise,调用处也没有加await等待执行完成,createUser中拿到的imageUri始终是undefined,上传还没完成就已经执行了Firestore写入。 - 上传参数格式错误:Expo ImagePicker返回的是包含
uri、宽高属性的结果对象,不是可直接上传的二进制blob数据,直接把整个对象传给uploadBytes会导致存储的文件格式损坏。 - 未主动获取访问URL:Firebase Storage上传完成后不会自动返回可公开访问的HTTP链接,需要单独调用API获取下载地址。
- 额外语法错误:
addDoc方法仅接收2个参数,你把页面导航写在第三个参数位置不会被执行。
修复方案
第一步:修正导入项,补全uploadImage逻辑
首先在Firebase导入区补充需要的方法,再重写上传逻辑:
// 补充导入getDownloadURL import { ref, uploadBytes, getDownloadURL } from "firebase/storage"; const uploadImage = async () => { // 未选择图片直接返回null if (!image?.uri) return null; // 将本地图片转为blob二进制格式 const fetchRes = await fetch(image.uri); const imageBlob = await fetchRes.blob(); // 文件名加时间戳避免重名覆盖 const fileExt = image.uri.split('.').pop(); const storageRef = ref(storage, `images/${Date.now()}.${fileExt}`); // 等待上传完成 const uploadSnapshot = await uploadBytes(storageRef, imageBlob); // 获取可公开访问的下载链接 const publicUrl = await getDownloadURL(uploadSnapshot.ref); return publicUrl; };
第二步:修正createUser异步逻辑与参数写法
const createUser = async () => { // 等待上传完成拿到真实URL const imageUri = await uploadImage(); await addDoc( usersCollectionRef, { name: name || null, cep: cep || null, logradouro: logradouro || null, numero: numero || null, bairro: bairro || null, uf: uf || null, image: imageUri || null, } ); // 写入完成后再执行页面跳转 navigation.navigate("HomeScreen"); };
内容的提问来源于stack exchange,提问作者Arthur Prasniski
相关产品推荐
相关产品推荐

