How to properly upload image to Firebase Storage and save link to firestore
You need to wait until the file has been completely uploaded before you can request its download URL.
storageRef.put(file).then(() => {
firebase.storage().ref("users").child(user.uid).getDownloadURL()
.then((downloadURL) => {
...
Upload Images to Firebase Storage and store a link in Firebase Database
You have to call the listener to get the download uri from firebase storage. Use following code to do that. Read the docs
filereference.putFile(imageuri)
.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Toast.makeText(Upload_Photos.this, "Upload Successfully", Toast.LENGTH_SHORT).show();
filepath.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
@Override
public void onSuccess(Uri uri) {
Uri downloadUrl = uri;
Upload upload = new Upload(name.getText().toString().trim(),downloadUrl.toString());
progressDialog.show();
String uploadId = mDatabaseref.push().getKey();
mDatabaseref.child(uploadId).setValue(upload);
progressDialog.setCanceledOnTouchOutside(false);
progressDialog.dismiss();
}
});
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
}
})
.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
@Override
public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
double progress = (100.0*taskSnapshot.getBytesTransferred())/taskSnapshot.getTotalByteCount();
progressDialog.setCanceledOnTouchOutside(false);
progressDialog.setMessage("Uploaded " +(int)progress+"%");
}
});
When uploading a image for one user to firebase storage, the link of the image updates for every user in database
According to your last comment:
Yes, Firebase email Authentication
Then you should consider saving user data, under the UID that comes from the authentication process and not under a pushed ID, as I see in your screenshot now. This means that you should add a User object to the database using:
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference usersRef = rootRef.child("users");
usersRef.child(uid).setValue(userObj).addOnCompleteListener(/* ... /*);
And not using:
usersRef.push().setValue(userObj).addOnCompleteListener(/* ... /*);
That beeing said, to be able to update the image that is uploaded to the node of the logged-in user, then please use the following updated method:
final StorageReference strRef = storageReference.child("users/"+ email_i +"/profile.jpg");
strRef.putFile(image_uri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Toast.makeText(getApplicationContext(), "Image has been uploaded", Toast.LENGTH_LONG).show();
strRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
@Override
public void onSuccess(Uri uri) {
Picasso.get().load(uri).fit().into(profPic);
imgRef = uri.toString();
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference usersRef = rootRef.child("users");
Map<String, Object> updates = new HashMap<String, Object>();
updates.put("profile_url", imgRef);
usersRef.child(uid).updateChildren(updates).addOnSuccessListener(/* ... /*);
}
});
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull /*@org.jetbrains.annotations.NotNull*/ Exception e) {
Toast.makeText(getApplicationContext(), "Failed to update profile picture", Toast.LENGTH_LONG).show();
}
});
See, there is no for-loop involed? That was causing you trouble, as it was updating all child under "users" node.
Uploading Image to Firebase Storage and Database
Organize your upload
and save
funcs like this:
func uploadMedia(completion: @escaping (_ url: String?) -> Void) {
let storageRef = FIRStorage.storage().reference().child("myImage.png")
if let uploadData = UIImagePNGRepresentation(self.myImageView.image!) {
storageRef.put(uploadData, metadata: nil) { (metadata, error) in
if error != nil {
print("error")
completion(nil)
} else {
completion((metadata?.downloadURL()?.absoluteString)!))
// your uploaded photo url.
}
}
}
Next just connect to FIRDatabase
and save it to your node.
@IBAction func addPost(_ sender: Any) {
if self.titleText.text != "" && self.authorText.text != ""
&& self.mainText.text != "" && self.dateText.text != "" {
uploadMedia() { url in
guard let url = url else { return }
ref?.child("Posts").childByAutoId().setValue([
"Title" : titleText.text,
"Article" : mainText.text,
"Author" : authorText.text,
"Date" : dateText.text,
"myImageURL" : url
])
}
}
You can also look at my answer about uploading data and saving URL's to database
Upload in Firebase Storage and fetch link to add it in Realtime Database
Issue
This appears to be a state mutation in the uploadImages
callback. A reference to the imagesUriArray
state is cached locally, mutated (i.e. direct push into array), and then the same reference is saved back into state. This doesn't trigger react to rerender with any updated state value.
const uploadImages = () => {
...
pictures.forEach( async (obj) => {
const id = obj.id
const uri = obj.uri
const response = await fetch(uri);
const blob = await response.blob();
var ref = storageUpload(storage, path)
await uploadBytes(ref, blob, metadata)
await getDownloadURL(ref)
.then((metadata) => {
let array = imagesUriArray // <-- reference to state
let object = {
"id": id,
"uri": metadata
}
array.push(object) // <-- state mutation
setImageUriArray(array) // <-- same state reference
})
.catch((error) => {
console.log(error)
});
})
};
Solution
Use a functional state update to update from the previous state. Create a shallow copy of the previous state and append the new data.
const uploadImages = () => {
...
pictures.forEach( async (obj) => {
const { id, uri } = obj;
const response = await fetch(uri);
const blob = await response.blob();
const ref = storageUpload(storage, path);
await uploadBytes(ref, blob, metadata);
await getDownloadURL(ref)
.then((uri) => {
setImageUriArray(imagesUriArray => [
... imagesUriArray, // <-- shallow copy
{ id, uri }, // <-- append new object
]);
})
.catch(console.log);
})
};
Update
uploadImages
needs to return a Promise so that addItem
can wait for it to complete its asynchronous code. addItem
also needs to access the updated imagesUriArray
that uploadImages
updates.
Map the pictures
array to an array of Promises (i.e. an async
fetchImageUri
function) that eventually returns the object with id
and new uri
properties.
const uploadImages = () => {
...
const fetchImageUri = async ({ id, uri }) => {
try {
const response = await fetch(uri);
const blob = await response.blob();
const ref = storageUpload(storage, path);
await uploadBytes(ref, blob, metadata);
const newUri = await getDownloadURL(ref);
return { id, uri: newUrl };
} catch(error) {
console.log(error);
}
}
return Promise.all(pictures.map(fetchImageUri));
};
Update addItem
to wait for the resolved array of Promises that contain the uploaded image data. Enqueue the imagesUriArray
state update here, then continue the rest of the function referencing the returned uploadedImages
array from uploadImages
.
const addItem = async () => {
const uploadedImages = await uploadImages();
setImageUriArray(imagesUriArray => [
...imagesUriArray, // <-- shallow copy
...uploadedImages, // <-- append new objects
]);
const changes = ref(db, path);
get(changes).then(async (snapshot) => {
if (snapshot.val().data !== undefined) {
const fetchedArray = snapshot.val().data;
const object = {
id: `${Math.random()}`,
images: uploadedImages,
};
update(changes, { data: [...fetchedArray, object] });
}
});
}
Related Topics
Swift Optional Inout Parameters and Nil
Retrieving Image from Firebase Storage Using Swift
Cllocationcoordinate2D Can't Be Instantiated
Get Description of Emoji Character
Nsfontattributedstring Worked Before Xcode 6.1
Swift Cross Compile to Single Linux Binary
How to Convert Hex Number to Bin in Swift
Swift - How to Mutate a Struct Object When Iterating Over It
Command Compileswiftsources Failed With a Nonzero Exit Code Xcode 10
Multiple Workers in Swift Command Line Tool
Retrieve Only 5 Users At a Time :Firebase [Like Instagram]
How to Create Custom Notifications in Swift 3
How to Create a Fixed-Size Array of Objects
Try, Try! & Try? What's the Difference, and When to Use Each
Swiftui - Is There a Popviewcontroller Equivalent in Swiftui