I'm new to firebase and I'm facing a problem here.
I have successfully uploaded my image to firebase storage already, however, I need to get the downloadurl at once and post it to the database. And I'm not sure why it doesn't work within that closure.
The following is my code:-
func CreateNewChatRoom(user: User, caption: String, data: Data){
let filePath = "\(user.uid)/\(Int(NSDate.timeIntervalSinceReferenceDate)).jpg"
let metaData = StorageMetadata()
metaData.contentType = "image/jpg"
let reference = storageRef.child(filePath)
reference.putData(data, metadata: metaData) { (metadata, error) in
if let error = error {
print("\(error.localizedDescription)")
return
}
reference.downloadURL(completion: { (url, error) in
if let error = error{
print("Error : \(error.localizedDescription)")
return
}
else{
if let downloadURL = url?.absoluteString {
let idRoom = self.BASE_REF.child("rooms").childByAutoId()
idRoom.setValue(["caption":caption, "thumbnailUrlFromStorage": self.storageRef.child(metadata!.path!).description,"fileUrl": downloadURL])
}
}
})
}
}
I have the same problem, and I found the following solution,
I hope it is useful to someone.
Swift 5
import FirebaseAuth
import FirebaseStorage
import FirebaseFirestore
typealias AddStoryResult = (Bool, Error?) -> Void
typealias UploadImageResult = (StorageMetadata?, Error?) -> Void
class StoryFirebaseAPI {
static let storage = Storage.storage()
static var downloadUrlString: URL?
var image: UIImage?
let photoUri = "smth uri path"
uploadImage(image, photoUriString: photoUri) { (metadata: StorageMetadata?, error: Error?) in
guard let metadata = metadata else {
if let error = error {
print("Error occured: \(error)")
}
completion(false, error)
return
}
// and at this point I have print(downloadUrlString)
completion(true, nil)
}
}
extension StoryFirebaseAPI {
func uploadImage(_ image: UIImage, photoUriString: String, completion: #escaping UploadImageResult) {
guard let imageData = image.jpegData(compressionQuality: 0.5) else {
print("smth error")
completion(nil, nil)
return
}
let storageRef = storage.reference().child(photoUriString)
let imageMetadata = StorageMetadata()
imageMetadata.contentType = "image/jpeg"
storageRef.putData(imageData, metadata: imageMetadata) { (storageMetadata, error) in
if let error = error {
print("Error: \(error.localizedDescription)")
completion(nil, error)
return
}
guard let unwrappedMetadata = storageMetadata else {
print("smth error")
print("Error: \(error?.localizedDescription ?? "")")
completion(nil, error)
return
}
storageRef.downloadURL { url, error in
if let error = error {
print("Error: \(error.localizedDescription)")
completion(nil, error)
return
} else {
if let url = url {
downloadUrlString = url
completion(unwrappedMetadata, nil)
}
}
}
print("Image uploaded successfully")
}
}
}
Related
I'm trying to upload a video file using phpickerviewcontroller, but I'm running into an issue uploading the URL to FirebaseStorage. Here is some code:
func uploadVideo(videoURL: URL)
{
let storage = Storage.storage()
let storageRef = storage.reference()
let videoRef = storageRef.child("rPosts/\(uid!)/\(fileID)")
let metadata = StorageMetadata()
metadata.contentType = "video/quicktime"
var videoData: Data = Data()
do
{
videoData = try Data(contentsOf: videoURL)
}
catch
{
print(error.localizedDescription)
return
}
videoRef.putData(videoData, metadata: metadata)
{ (metaData, error) in
guard error == nil else
{
self.errorLabel.text = error!.localizedDescription
return
}
}
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult])
{
dismiss(animated: true, completion: nil)
guard let itemProvider = results.first?.itemProvider else { return }
itemProvider.loadItem(forTypeIdentifier: "com.apple.quicktime-movie", options: nil)
{ (videoFile, error) in
guard error == nil else { return }
let videoFile = videoFile as? URL
DispatchQueue.main.async
{
self.uploadVideo(videoURL: videoFile!)
print(videoFile!)
}
self.uploadedYet = true
}
}
I've tried using .putFile but it keeps on saying
Ensure file URL is not a directory, symbolic link, or invalid url.
When I use .putData it says
The file "..." couldn’t be opened because there is no such file
EDIT:
itemProvider.loadFileRepresentation(forTypeIdentifier: "com.apple.quicktime-movie")
{ (videoURL, error) in
guard error == nil else { return }
print("isbeingcalled") //does not get calleed :(
DispatchQueue.main.async
{
let storageRef = Storage.storage().reference()
let videoRef = storageRef.child("rPosts/\(self.uid!)/\(self.fileID).mov")
let metadata = StorageMetadata()
metadata.contentType = "video/quicktime"
print("run")
videoRef.putFile(from: videoURL!, metadata: metadata)
{ (metaData, error) in
guard error == nil else
{
print(videoURL!)
print(videoRef.fullPath)
self.errorLabel.text = error!.localizedDescription
print(error!.localizedDescription)
return
}
}
}
self.uploadedYet = true
}
I have an image that is uploaded to the Firebase Storage but I can not get the downloadURL of this to save it in my database.
I already read a lot of posts on StackOverflow but there was nothing working out for me. The image is loaded into the storage but the error says that it is not existing.
let image = self.selectedImage
let imageData = UIImageJPEGRepresentation(image, 0.1)
let storageRef = Storage.storage().reference().child(uid)
storageRef.putData(imageData, metadata: nil) // i know that i can use a completion here but i left it for now
storageRef.downloadURL { url, error in
if let error = error {
print(error)
} else {
// do sth. else
}
}
These are the errors that I get:
FIRStorageErrorDomain Code=-13010 "Object W002MjRvi0d8JfVwImUJhH0ph2O2 does not exist."UserInfo={object=W002MjRvi0d8JfVwImUJhH0ph2O2,
ResponseBody={
"error": {
"code": 404,
"message": "Not Found. Could not get object"
}
}
ResponseErrorDomain=com.google.HTTPStatus, ResponseErrorCode=404}
Please check Storage Rules
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth!=null;
}
}
}
In Your ViewController
import Firebase
import FirebaseAuth
import ImageIO
var imgData: NSData = NSData(data: UIImageJPEGRepresentation((self.img_Photo?.image)!, 0.5)!)
self.uploadProfileImageToFirebase(data: imgData)
func uploadProfileImageToFirebase(data:NSData){
guard let userID = Auth.auth().currentUser?.uid else {
return
}
let storageRef = Storage.storage().reference().child(“Images”).child(userID)
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 for 'images/stars.jpg'
let urlStr:String = (url?.absoluteString) ?? ""
}
}
})
}
}
When using an image picker to grab the image selected and place in firebase storage I want to be able to download the URL and take place of the profile image inside the app. Unfortunately, when the process reaches the URLSession in the script nothing happens. There is not an error display nor does it dispatchQueue. The app will not crash but just skip over everything. Any ideas or suggestions to a code fix?
if let profileImageUploadedData = self.profileImage.image, let uploadData = profileImage.image?.jpegData(compressionQuality: 0.1)
{
storageRef.putData(uploadData, metadata: nil, completion: { (metadata, error) in
if error != nil
{
print("Downdloading putData Error: \(error!.localizedDescription)")
return
}
storageRef.downloadURL(completion: { (url, error) in
if error != nil
{
print("DownloadURL ERROR \(error!.localizedDescription)")
return
}
if let profileImageUrl = url?.absoluteString
{
print("Profile image uploading...")
let values = ["profileImageUrl": profileImageUrl]
let url = URL(fileURLWithPath: profileImageUrl)
URLSession.shared.dataTask(with: url) { (data, response, error) in // ERROR OCCURING NEED TO FIX
if error != nil
{
print("* URL SESSIONS ERROR: \(error!)")
return
}
DispatchQueue.main.async
{
print("Trying to register profile")
self.registerUserIntoDatabaseWithUID(uid: uid, values: values as [String : AnyObject])
self.profileImage.image = UIImage(data: data!)
print("Dispatch: \(data!)")
}
print("Profile image successfull uploaded to storage")
}
}
})
}).resume()
print("** Profile Image Data Uploaded:\(profileImageUploadedData)")
}
}
func registerUserIntoDatabaseWithUID(uid: String, values: [String: AnyObject])
{
print("Registering to database")
let dataReference = Database.database().reference(fromURL: "URL String")
let usersReference = dataReference.child("users").child(uid)
usersReference.updateChildValues(values, withCompletionBlock: { (err, reference) in
if err != nil
{
print(err!)
return
}
// self.profileImage.image = values["profileImageUrl"] as? UIImage
// self.fetchProfileImage()
self.dismiss(animated: true, completion: nil)
print("Saved user sussccessfully in database")
})
}
}
This is a big question that is actually asking for a number of different answers so let's just focus on one;
How to authenticate a user, get a url stored in Firebase Database that
references an image stored in Firebase Storage, then download that
image.
Here we go
First - authenticate a user
Auth.auth().signIn(withEmail: user, password: pw, completion: { (auth, error) in
if let x = error {
//handle an auth error
} else {
if let user = auth?.user {
let uid = user.uid
self.loadUrlFromFirebaseDatabase(withUid: uid)
}
}
})
now the user is authenticated, get the image location url from Firebase Database
func loadUrlFromFirebaseDatabase(withUid: String) {
let thisUserRef = self.ref.child("users").child(withUid)
let urlRef = thisUserRef.child("url")
urlRef.observeSingleEvent(of: .value, with: { snapshot in
if let url = snapshot.value as? String {
self.loadImageUsingUrl(url: url)
} else {
print("no image for user")
}
})
}
Now that we have the location of the image in Firebase Storage, get it
func loadImageUsingUrl(url: String) {
let storage = Storage.storage()
let imageRef = storage.reference(forURL: url)
imageRef.getData(maxSize: 1 * 1024 * 1024) { data, error in
if let error = error {
print("error downloading \(error)")
} else {
if let image = UIImage(data: data!) {
//do something with the image
} else {
print("no image")
}
}
}
}
Here is the code that I'm using
#objc func handleSignUp() {
guard let email = emailTextField.text, email.characters.count > 0 else { return }
guard let username = usernameTextField.text, username.characters.count > 0 else { return }
guard let password = passwordTextField.text, password.characters.count > 0 else { return }
Auth.auth().createUser(withEmail: email, password: password, completion: { (user, error) in
if let err = error {
print("Failed to create user:", err)
return
}
print("Successfully created user:", user?.user.uid)
// guard let image = self.plusPhotoButton.imageView?.image else { return }
// guard let uploadData = UIImageJPEGRepresentation(image, 0.3) else { return }
guard let uploadData = self.plusPhotoButton.imageView?.image?.jpegData(compressionQuality: 0.3) else{return}
let filename = NSUUID().uuidString
Storage.storage().reference().child("profile_images").child(filename).putData(uploadData, metadata: nil, completion: { (metadata, err) in
if let err = err {
print("Failed to upload profile image:", err)
return
}
//this code isn't correct for swift4.2
//guard let profileImageUrl = metadata?.downloadURL()?.absoluteString else { return }
func getDownloadURL(from path: String, completion: #escaping (URL?, Error?) -> Void) {
let storageReference = Storage.storage().reference(forURL: "gs://instagramfirebase-60be5.appspot.com")
let storageRef = storageReference.child(path).downloadURL(completion: completion)
}
print("Successfully uploaded profile image")//,profileImageUrl
guard let uid = user?.user.uid else { return }
let dictionaryValues = ["username": username] as [String : Any]//, "profileImageUrl": profileImageUrl
let values = [uid: dictionaryValues]
Database.database().reference().child("users").updateChildValues(values, withCompletionBlock: { (err, ref) in
if let err = err {
print("Failed to save user info into db:", err)
return
}
print("Successfully saved user info to db")
})
})
})
}
Snapshots are as followed :
I am confused about how to get the imageUrl from firebase storage and store it in firebase database in Xcode 10 swift 4.2
Please help, Thank you for your time.
You can get the download url easily by using the following code inside the closure of your image-upload:
storageRef.downloadURL(completion: { (url, error) in
if let err = error{
// error happened - implement code to handle it
print(err)
} else {
// no error happened; so just continue with your code
print(url?.absoluteString) // this is the actual download url - the absolute string
}
Please note: Don't store the downloadURL on its own as Firebase can change tokens of the downloadURL, I'd suggest to always grab a hold of the full storage path.
I hope I was able to help.
I have a some problem with old syntax like:
metadata?.downloadURL()?.absoluteString"
How to use new way in my code?
Error in this part code:
let downloadURL = metadata?.storageReference?.downloadURLWithCompletion()
Full code:
Storage.storage().reference().child(imgUid).putData(imgData, metadata: metadata) { (metadata, error) in
if error != nil {
print("Did'n upload image")
} else {
print("uploaded")
let downloadURL = metadata?.storageReference?.downloadURLWithCompletion()
if let url = downloadURL {
self.setUser(img: url)
}
}
}
This is a easyway to do this use this Func to save the data to the FirebaseStorage then take the url as a String then you can save it on
func uploadImageToFirebaseStorage(data: Data, onSuccess: #escaping (_ imageUrl: String) -> Void) {
let photoIdString = NSUUID().uuidString
let storageRef = Storage.storage().reference(forURL: Config.STORAGE_REF_URL).child(POST_REF).child(photoIdString)
storageRef.putData(data, metadata: nil) { (metadata, error) in
if let error = error {
debugPrint(error.localizedDescription)
return
}
metadata?.storageReference?.downloadURL(completion: { (url, error) in
if let error = error {
print(error.localizedDescription)
return
}
onSuccess("\(url!)")
})
}
}
func save() {
let newPostRef = Database.database().reference().child("users").childByAutoId()
let newPostKey = newPostRef.key
// 1. save image
if let imageData = self.profilPic!.jpegData(compressionQuality:0.5) {
let storage = Storage.storage().reference().child("profileImages")
DispatchQueue.main.sync {
storage.putData(imageData).observe(.success, handler: { (snapshot) in
storage.downloadURL(completion: { (url, error) in
if error != nil {
print(error!.localizedDescription)
return
}
if let profileImageUrl = url?.absoluteString {
guard let uid = (Auth.auth().currentUser?.uid) else {return}
let values = ["name": self.name, "email": self.email, "profilePictureUrl": profileImageUrl]
newPostRef.setValue(values)
self.ref.child(uid).childByAutoId().setValue(values)
}
})
})
}
}
}