使用Expo React Native实现用户图片上传至Firebase并展示的问题咨询
Hey there! Let's tackle your questions one by one— I’ve been in the exact same boat building Expo + Firebase apps, so I know the pain points here.
First off: your current code is uploading the image file to Firebase Storage! The XHR-to-Blob approach you’re using is the correct way to handle local file URIs with the Firebase Web SDK. But there’s a critical mistake you’re making: you’re saving the temporary local device URI (file:///...) to your Firestore user collection instead of the permanent Firebase download URL.
To verify the upload worked:
- Head to your Firebase Console → Open your project → Go to Storage → Check the root directory for files named
images[random-number](the naming you used inchild("images" + Math.random())). - Alternatively, modify your
uploadImageAsyncfunction to log the download URL, then paste that URL into a browser. If it loads your image, the upload was successful:async function uploadImageAsync(uri) { // ... your existing blob code ... const downloadURL = await snapshot.ref.getDownloadURL(); console.log("Image live URL:", downloadURL); // Add this line return downloadURL; }
The big fix here: save the downloadURL (not the local URI) to your Firestore user document. Local URIs are only valid on the device that took the photo—they’ll break if the user clears app cache or switches devices.
putFile() or put(uri) isn't working? Let’s break down the errors:
putFile is not a function: This method doesn’t exist in the Firebase Web SDK (which you’re using with Expo).putFileis a feature of the Firebase Admin SDK or React Native Firebase (RNFB) storage module, but not the standard web SDK.put(uri)fails: Theput()method expects binary data (Blob, File, or ArrayBuffer) as input—not a string URI. Yourfile://path is just a pointer to the file on your device, not the file data itself, so the SDK can’t process it directly.
Your XHR approach works, but using Expo’s FileSystem module is more idiomatic and simpler for Expo apps. Here’s a revised version that fixes your storage issue and uses Expo tools:
First, install the module if you haven’t:
npx expo install expo-file-system
Then update your code:
import * as FileSystem from 'expo-file-system'; import firebase from 'firebase/app'; // Ensure this is imported const handleImagePicked = async (pickerResult) => { try { if (!pickerResult.cancelled) { setImage(pickerResult.uri); const downloadURL = await uploadImageAsync(pickerResult.uri); // Save the permanent URL to Firestore (adjust your collection path as needed) const currentUser = firebase.auth().currentUser; if (currentUser) { await firebase.firestore() .collection('users') .doc(currentUser.uid) .update({ profileImage: downloadURL }); } console.log("Upload done, URL saved to user profile!"); } } catch (e) { console.log(e); alert("Upload failed, sorry :("); } }; async function uploadImageAsync(uri) { // Extract file extension to preserve image type (e.g., jpg, png) const fileExtension = uri.split('.').pop(); // Create an organized filename (easier to manage user images later) const fileName = `user-profiles/${firebase.auth().currentUser.uid}/${Date.now()}.${fileExtension}`; const storageRef = firebase.storage().ref().child(fileName); // Convert local file to Blob using Expo FileSystem const base64String = await FileSystem.readAsStringAsync(uri, { encoding: FileSystem.EncodingType.Base64, }); const blob = new Blob( [Uint8Array.from(atob(base64String), char => char.charCodeAt(0))], { type: `image/${fileExtension}` } ); // Upload the Blob to Firebase Storage const snapshot = await storageRef.put(blob); blob.close(); // Clean up the Blob to free memory // Return the permanent download URL return await snapshot.ref.getDownloadURL(); }
- Saves the permanent Firebase download URL to your user’s Firestore document (no more broken local URIs).
- Uses Expo’s
FileSystemfor simpler Blob conversion (no messy XHR code needed). - Creates a structured storage path (
user-profiles/{uid}/{timestamp}.ext) to keep user images organized. - Preserves the original file extension, so Firebase recognizes the correct image type.
Later, when you fetch the user’s data from Firestore, use the saved profileImage URL directly in your Image component:
<Image source={{ uri: userData.profileImage }} style={{ width: 150, height: 150, borderRadius: 75 }} />
内容的提问来源于stack exchange,提问作者S. N

