I have a video creating process where a user selects a video using UIImagePickerController. After selecting a video, the url of the video is passed to the video details page. Once the user completes the details and clicks upload, I run this code:
if canProceed(){
let fileName = "\(UUID().uuidString).mov"
storage.reference(withPath: "videos/\(Auth.auth().currentUser?.email ?? "")/\(fileName)").putFile(from: vidURL, metadata: nil) { metadata, err in
if err != nil{
print(err)
return
}
metadata?.storageReference?.downloadURL(completion: { url, err in
if err != nil{
print(err)
return
}
db.collection("reelPool").document(fileName).setData(["url": url])
})
}
}
Nothing is uploaded to cloud storage and the return is:
Error Domain=FIRStorageErrorDomain Code=-13000 "An unknown error occurred, please check the server response."
HI I think Here is your answer Just try with it ,
// Url is Video Url Which you will get when Pick a video from Image Picker
func upload(file: URL, completion: #escaping ((_ url : URL?) -> ())) {
let name = "\(yourFile Name)).mp4"
do {
let data = try Data(contentsOf: file)
let storageRef =
Storage.storage().reference().child("Videos").child(name)
if let uploadData = data as Data? {
let metaData = StorageMetadata()
metaData.contentType = "video/mp4"
storageRef.putData(uploadData, metadata: metaData
, completion: { (metadata, error) in
if let error = error {
completion(nil)
}
else{
storageRef.downloadURL { (url, error) in
guard let downloadURL = url else {
completion(nil)
return
}
completion(downloadURL)
}
print("success")
}
})
}
}catch let error {
print(error.localizedDescription)
}
And then You will get Url of the Video, now run code of firestore and Pass Url in dictionary .
Did you remember to edit your Firestore rules to allow for read/write access? Your database may not allow writing or only allow writing for authenticated users. Typically Code -13000 is related to permissioning issues on the database.
Related
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"))
}
}
In my app user presses the button to take the photo and then it uploads to firebase storage but every time I do a new photo the old one disappears and it replaces itself with the same url string as old one had before. How can I upload a new image every time the same user takes and uploads the photo?
Here is the code
let storage = Storage.storage().reference()
guard let imageData = ecoImage.jpegData(compressionQuality: 0.75) else {
return
}
let metaData = StorageMetadata()
metaData.contentType = "image/jpg"
storage.child("pins/\("Eco1")").putData(imageData, metadata: metaData) { (meta, error) in
if let err = error {
print(err.localizedDescription)
} else {
storage.child("pins/\("Eco1")").downloadURL { (url, err) in
if let e = err {
print(e.localizedDescription)
} else {
let urlString = url?.absoluteString
doc.setData(["uid": uid, "pinLocation": ecoPin, "time": timeData, "url": urlString!]) { (error) in
if error != nil {
print(error?.localizedDescription)
return
} else {
print("Pin saved")
}
}
}
}
}
print("Image sent")
}
You need to generate the random file name for every time you put the new photo.
In the code you provided, after the metadata, declare the variable with UUID.
let fname = UUID.init().uuidString.replacingOccurences(of: "-", with: "")
storage.child("pins/\(fname))...so on
This will generate the random file name each time you upload, and supposedly not replace your previous photo.
I am trying to allow users to upload a profile photo to Firebase Storage. The image gets uploaded during the sign up process of my app. The image is being uploaded to Firebase Storage properly, however, the download URL is not uploading to Google Cloud Firestore.
I've already tried to change my variable downloadURL of type String to hold an empty String. This did not change the result.
Here is the code to upload the profile photo to Firebase Storage:
func uploadProfilePic() -> String {
guard let imageData = profilePic?.jpegData(compressionQuality: 0.75) else {
print("Unable to get image data.")
return ""
}
let imageID = UUID().uuidString
let profilePhotosRef = Storage.storage().reference().child("profilePhotos/\(imageID).jpg")
let uploadMetadata = StorageMetadata()
uploadMetadata.contentType = "image/jpeg"
var downloadURL = String()
profilePhotosRef.putData(imageData, metadata: uploadMetadata) { (downloadMetadata, err) in
if let err = err {
self.showAlertWithOK(title: "An Error Occurred", message: "There was an error uploading your profile photo. Try again later in Hostend settings.")
print("An error occurred: \(err.localizedDescription)")
}
profilePhotosRef.downloadURL { (url, err) in
if let url = url {
downloadURL = url.absoluteString
}
}
}
return downloadURL
}
Here is the code for uploading the profile photo download URL to Cloud Firestore:
db.collection("users").document(uid).setData(["profile_pic_url": uploadProfilePic(), "name": name, "phone_number": phoneNumber, "fcm_token": token, "timestamp": Date()])
The uploadProfilePic() method returns a String.
I expected the download URL of the image to be uploaded to Firestore under "profile_pic_url," but that did not happen. Instead, it is just an empty String even though the image had been successfully to Firebase Storage.
You can't use a return statement for a function that contains a closure as the function will return before the closure has executed.
Instead change your function to use a completion handler such as
func uploadProfilePic(completion: #escaping (String?, Error?) -> ()) {
Then once you get your download url call the handler.
profilePhotosRef.downloadURL { (url, err) in
completion(url, err)
}
You can then use this function to populate your call to Cloud Firestore like so
self.uploadProfilePic() { (url, error) in
guard error....
if let url = url {
// do your upload here
}
}
I'm getting an error with firebase and my code.
Type 'StorageReference' has no member 'put'
I tried putData and still nothing. what is the best solution to fix this problem?
I'm also getting this error when users tap to pick a profile picture
'UIImageJPEGRepresentation' has been replaced by instance method
'UIImage.jpegData(compressionQuality:)'
StorageReference.put(imageData, metadata: nil, completion: { (metadata, error) in
if let profileImg = self.selectedImage, let imageData = UIImageJPEGRepresentation(profileImg, 0.1)
theres a article how to upload data to storage on firebase:
https://firebase.google.com/docs/storage/ios/upload-files
// Upload the file to the path "images/rivers.jpg"
let uploadTask = riversRef.putData(data, metadata: nil) { (metadata, error) in
guard let metadata = metadata else {
// Uh-oh, an error occurred!
return
}
// Metadata contains file metadata such as size, content-type.
let size = metadata.size
// You can also access to download URL after upload.
riversRef.downloadURL { (url, error) in
guard let downloadURL = url else {
// Uh-oh, an error occurred!
return
}
}
}
For some reason, when I am using firebase storage to retrieve my download image URL (I have confirmed that the image is actually sent to firebase storage), the url is returning nil. I'm pretty sure my file path matches/is correct but I'm not sure where I'm going wrong on this.
let selectedImageData=UIImageJPEGRepresentation(selectedImage.image!, 1)
let storageRef=Storage.storage().reference()
let metadata=StorageMetadata()
storageRef.child("Users").child(Auth.auth().currentUser!.uid)
.child("Pictures"+String(self.tracker)).putData(selectedImageData!, metadata: metadata)
{
(metadata, error) in
if error != nil{
print("There was a problem uploading")
return
}
storageRef.child("Users").child(Auth.auth().currentUser!.uid)
.child("Pictures"+String(self.tracker)).downloadURL(completion:
{
(url, error) in
print("What's going on")
self.pictures.append((url?.absoluteString)!)
})
}
Use the below code to upload image to Storage and get a return path for the image
let selectedImageData=UIImageJPEGRepresentation(selectedImage.image!, 1)
self.uploadProfileImageToFirebase(data: selectedImageData)
func uploadProfileImageToFirebase(data:NSData){
let storageRef = Storage.storage().reference().child("Users").child(Auth.auth().currentUser!.uid).child("Pictures").child(String(self.tracker))
//Modify the above line as per your requirement
if data != nil {
storageRef.putData(data as Data, metadata: nil, completion: { (metadata, error) in
if(error != nil){
print(error)
return
}
// Fetch the download URL
storageRef.downloadURL { url, error in
if let error = error {
// Handle any errors
if(error != nil){
print(error)
return
}
} else {
// Get the download URL
let urlStr:String = (url?.absoluteString) ?? ""
print(urlStr)
}
}
})
}
Seems like your reference for putData and for getting downloadURL is different some how, maybe the tracker is changing in the meantime?
To avoid the reference being different let's try changing your code like this:
let selectedImageData=UIImageJPEGRepresentation(selectedImage.image!, 1)
let storageRef=Storage.storage().reference()
let metadata=StorageMetadata()
let reference = storageRef.child("Users").child(Auth.auth().currentUser!.uid).child("Pictures"+String(self.tracker))
reference.putData(selectedImageData!, metadata: metadata) { (metadata, error) in
if error != nil{
print("There was a problem uploading")
return
}
reference.downloadURL { (url, error) in
print("Download error: \(error), url: \(url)")
self.pictures.append((url?.absoluteString)!)
}
}
Basically we make sure to use the same reference in both cases.