How to use "StorageReference.downloadURLWithCompletion()" in Firebase? - ios

Hi I have Question about making ios Application wiht Firebase
Nowadays I am making a chat Application using watching an YouTube
https://www.youtube.com/watch?v=MJ1r5jjdf4Q&index=4&list=PLmdU__e_zPf9uczwNhLNANvxT5mzxMiXQ
In here
At the Source code, let imageUrl = data?.downloadURL()?.absoluteString this got an error "Value of type 'StorageMetadata' has no member 'downloadURL'"
I heard the downloadURL() was deprecated in Firebase So, docs said using StorageReference.downloadURLWithCompletion() instead of downloadURL.
But I don't know how to change the code.
Please tell me how to change the code. And chage the code
Thank you!
func signupEvent(){
Auth.auth().createUser(withEmail: email.text!, password: password.text!){(user,err) in
let uid = user?.user.uid
let image = UIImageJPEGRepresentation(self.imageView.image!, 0.1)
Storage.storage().reference().child("userImage").child(uid!).putData(image!, metadata:nil, completion:{(data, error) in
let imageUrl = data?.downloadURL()?.absoluteString
Database.database().reference().child("users").child(uid).setValue(["name": self.name.text!, "profileImageUrl" : imageUrl])
})
}
}

You can check the updated documentation of Firebase 5 upload files here, the API changed so you should use StorageReference's downloadURL method.
So your code become something like this:
func signupEvent(){
Auth.auth().createUser(withEmail: email.text!, password: password.text!){(user,err) in
let uid = user?.user.uid
let image = UIImageJPEGRepresentation(self.imageView.image!, 0.1)
let storageItem = Storage.storage().reference().child("userImage").child(uid!)
storageItem.putData(image!, metadata:nil, completion:{(data, error) in
// Now is good to check errors
if error != nil {
print("Error: couldn't upload the image")
}
else {
storageItem.downloadURL(completion: { (url, error) in
if error != nil {
print(error!)
return
}
if url != nil {
let imageUrl = url!.absoluteString
Database.database().reference().child("users").child(uid).setValue(["name": self.name.text!, "profileImageUrl" : imageUrl])
}
}
}
})
}
}

Related

Display Image downloaded from downloadURL generated by Firebase

I need to display the images that have been stored on the storage on Firebase. Right now, I only tracked the images using the link generated by function downloadURL:
func UploadImage(imageData: Data, path: String, completion: #escaping (String) -> ()){
let storage = Storage.storage().reference()
let uid = Auth.auth().currentUser?.uid
storage.child(path).child(uid ?? "").putData(imageData, metadata: nil) { (_, err) in
if err != nil{
completion("")
return
}
// Downloading Url And Sending Back...
storage.child(path).child(uid ?? "").downloadURL { (url, err) in
if err != nil{
completion("")
return
}
completion("\(url!)")
}
}
}
So all I can get is a hyperlink that is like: https://firebasestorage.googleapis.com/v0/b/getting-started-20f2f.appspot.com/o/profile_Photos%2FGQ1KR9H1mLZl2NAw9KQcRe7d72N2?alt=media&token=473ce86c-52ba-42ec-be71-32cc7dc895d7.
I refer to the official documentation, it seems that only when I have the name of the image file can I download it to an ImageView or UIImageView object. However, the link does not make any sense to me, so what can I do?
EDIT
I actually tried a solution provided by the official documentation:
func imageDownloader(_ imageURL: String) {
let store = Database.database().reference()
let uid = Auth.auth().currentUser?.uid
let imageRef = store.child(imageURL)
var myImageView = UIImageView()
imageRef.getData(completion: { (error, data) in
if let error = error {
// Uh-oh, an error occurred!
} else {
// Data for "images/island.jpg" is returned
let image = UIImage(data: data!)
}
})
}
But it suggests that I need to change something because Cannot convert value of type 'DataSnapshot' to expected argument type 'Data'.
If you're storing the image paths in Firestore, actually the exact file name does not matter if there is only one file available under the fork. So you just need to specify the path.
To then download the image from Storage, construct the path and download:
let uid = Auth.auth().currentUser?.uid
Storage.storage().reference().child("the\path\to\your\uid\collection").child(uid).getData(maxSize: 1048576, completion: { (data, error) in
if let data = data,
let img = UIImage(data: data) {
// do something with your image
} else {
if let error = error {
print(error)
}
// handle errors
}
})
You are uploading to Storage.storage(), but then in your imageDownloader, you're attempting to use Database.database(), which has a similar-looking API, but is, in fact, different.
Make sure to use Storage.storage() and that the closure parameters are in the order data, error in.
Finally, right now in your imageDownloader, it doesn't look like you're doing anything yet with var myImageView = UIImageView(), but keep in mind that you won't have access to the UIImage until the async getData completes.
Store your images at Firebase Storage & then retrieve using this code.
Storage.storage().reference.child("ProfilePhotos").child("ImageName").downloadURL {(url, _) in
DispatchQueue.main.async {
guard let url = url else { return }
imageView.setImage(with: url, placeholder: UIImage(named: "dummyImage"))
}
}

Firebase Storage Warning: downloadURL()' is deprecated: Use `StorageReference.downloadURLWithCompletion()

I just updated my project to the latest version of Firebase Storage and I am now getting a warning:
downloadURL() is deprecated: Use StorageReference.downloadURLWithCompletion() to obtain a current download URL.
I looked at the Firebase image upload documentation but it still references using downloadURL() which is now depreciated. In the code below I am getting the download URL of the image as a String. The code works but now to be updated since downloadURL() is depreciated
uploadProfilePicTask.observe(.success) { snapshot in
guard let profilePicStringURL = snapshot.metadata?.downloadURL()?.absoluteString else { return }
...
Here is my attempted updated. I tried the code below with the new downloadURLWithCompletion() but something in snapshot.metadata?.storageReference? is returning nil so I am not able to retrieve the url String. Does anyone know how to use the new downloadURLWithCompletion() appropriately below?
uploadProfilePicTask.observe(.success) { snapshot in
snapshot.metadata?.storageReference?.downloadURL { URL, error in
if let urlString = URL?.absoluteString {
// Do something
} else {
return
}
}
Basically not using the metadata but instead just getting the url after the success of your observe event. Since it's successful and you know it's there, you can download the URL. It's there in their docs to 'Generate a download URL'. Below, I'm assuming your StorageReference is uploadProfilePicTask.
uploadProfilePicTask.downloadURL(completion: { (url, error) in
if (error == nil) {
if let downloadUrl = url {
// Make you download string
let downloadString = downloadUrl.absoluteString
}
} else {
// Do something if error
}
})
I had the same problem, but I fixed it with this code:
uploadTask.observe(.success) { snapshot in
guard let imageURL = snapshot.metadata?.storageReference?.downloadURL(completion: { (url, error) in if error != nil {
print(error as Any)
} else { //add all you want
}
}) else { return }
let imageStr = String(describing: imageURL)
DBService.manager.updatePhoto(profileImageUrl: imageStr)
AuthService.manager.updatePhoto(urlString: imageStr)
}
}

Firebase image object does not exist?

I am currently learning about how to upload/download images to/from Firebase. However, I am encountering two problems:
When I upload the image to my Firebase console it says it's type is "application/octet-stream" which is not exactly what I want (I uploaded a jpeg file)
Here's the code:
#IBAction func completeSignUpButton(_ sender: UIButton) {
let userProfileImageRef = storage.child("userProfileImage")
//UPloading the photo into firebase
let data = Data()
//uploading user profile picture
if self.userInitialPhoto.image != nil {
if let uploadData = UIImagePNGRepresentation(self.userInitialPhoto.image!) {
userProfileImageRef.putData(uploadData, metadata: nil, completion: { (metadata, error) in
if error != nil {
print(error?.localizedDescription)
return
} else {
print("Image upload success!")
//self.dismiss(animated: true, completion: nil)
self.performSegue(withIdentifier: "completeRegistrationSegue", sender: self)
}
})
}
} else {
print("You need to pick a picture!")
}
}
So this might be the problem that's causing my second problem:
When I try to load the image from Firebase to my UIImage in my app, it says Object Optional(\"userID\")/userProfileImage does not exist."
Here's my code for that:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
docRef = Firestore.firestore().collection("user Status").document("Current Status")
self.userStatusTableView.reloadData()
let referencePath = Storage.storage().reference(withPath: "\(userID)/userProfileImage")
let userProfileImageRef = Storage.storage().reference().child("\(userID)/userProfileImage")
userProfileImageRef.getData(maxSize: 1 * 1024 * 1024) { (data, error) in
if error != nil {
print("There's an eror downloading the image\(error?.localizedDescription)")
} else {
self.userProfileImage.image = UIImage(data: data!)
}
}
}
I am wondering what I should do to fix these issues.
Thanks for your help in advance and happy new year to you all.
while uploading the image to firebase you passed metadata as nil. you need to pass image metadata there
let metaData = FIRStorageMetadata()
metaData.contentType = "image/jpg"
and in upload complitionBlock, you can get URL for that image using
if error == nil , let meta = meta {
if let url = meta.downloadURL()?.absoluteString {
//use this url to access your image
}
}

Changing values in storage metadata in Firebase

In my iOS app, users can upload profile pictures which are upload to the storage in Firebase. I have saved the URL of the profile pictures on to the database so I can know which URLs correspond to which users using the following code:
let storageRef = FIRStorage.storage().reference()
let fileRef = storageRef.child("pages/").child(UUID().uuidString + ".jpg")
_ = fileRef.put(UIImageJPEGRepresentation(image, 0.75)!, metadata: nil) { (metadata, error) in
if let error = error {
SCLAlertView().showError("Error", subTitle: error.localizedDescription)
return
} else {
let downloadURL = metadata!.downloadURL()
let dictionary: [String: Any] = ["UserID": uid, "PageName": self.pageTitle.text!, "PFPURL": downloadURL!, "Tags": self.tags, "Likes": [uid]]
let reference = FIRDatabase.database().reference().child("Pages").childByAutoId()
reference.setValue(dictionary, withCompletionBlock: { (error, ref) in
if let error = error {
SCLAlertView().showError("Error", subTitle: error.localizedDescription)
return
}
self.performSegue(withIdentifier: "setupComplete", sender: self)
})
}
}
However, I would like these pictures to be editable. Is it possible I can replace the image in the storageRef yet still keep the same URL? If so, how would I accomplish that? Thanks!
You can't keep the same download URL. When the photo is edited, you'll need to update the value of "PFPURL" in the database to be the new URL.

Reference Firebase users in database with images in Firebase Storage Swift

Normally I would be able to find an answer to this question online but since its so new I have been having trouble.
When I have users sign into the app and they choose 4-5 pictures for their profile, how do I store those images in Firebase Storage and reference those images to that user in Firebase Database?
Thanks
You upload them to the Firebase Storage first and then store the url in Firebase Database
let storage = FIRStorage.storage()
let data: NSData = myImageData
let userProfilePic = storageRef.child("users/abc/profileimage.jpg")
let uploadTask = userProfilePic.putData(data, metadata: nil) { metadata, error in
if (error != nil) {
// Uh-oh, an error occurred!
} else {
let downloadURL = metadata!.downloadURL
// store downloadURL in db
storeUserProfileInDB(downloadURL)
}
}
func storeUserProfileInDB(profileImgUrl: NSURL) {
let ref = FIRDatabase.database().reference()
let key = ref.child("users").childByAutoId().key
let dictionaryUser = [ "userName" : name! ,
"imageUrl" : profileImgUrl.absoluteString,
]
let childUpdates = ["/users/\(key)": dictionaryTodo]
ref.updateChildValues(childUpdates, withCompletionBlock: { (error, ref) -> Void in
//save
})
}

Resources