Here are two ways I've tried to upload the file:
1.
getURLOfPhoto(assetURL: imagesDictionary[String(whichProfileImage)]! , completionHandler: { (responseURL) in
FIRStorage.storage().reference().putFile(responseURL as! URL)
})
2.
let assets = PHAsset.fetchAssets(withALAssetURLs: [imagesDictionary[String(whichProfileImage)] as! URL], options: nil)
let asset = assets.firstObject
asset?.requestContentEditingInput(with: nil, completionHandler: { (contentEditingInput, info) in
let imageFile = contentEditingInput?.fullSizeImageURL?
FIRStorage.storage().reference().child("test").putFile(imageFile!, metadata: nil) { (metadata, error) in
if let error = error {
return
}
}
})
I am getting this error:
Body file is unreachable: /var/mobile/Media/DCIM/100APPLE/picture.JPG
Error Domain=NSCocoaErrorDomain Code=257 "The file “picture.JPG” couldn’t be opened because you don’t have permission to view it."
UserInfo={NSURL=file:///var/mobile/Media/DCIM/100APPLE/picture.JPG, NSFilePath=/var/mobile/Media/DCIM/100APPLE/picture.JPG,
NSUnderlyingError=0x15da49a0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
The URL seems to be being retrieved successfully and the error only occurs when the putFile()
method gets called.
Does anyone know how to fix this error or another way of uploading a file (not a Data object) to Firebase Storage?
Thanks in advance
Currently Firebase Storage is unable to use file URLs that are retrieved using the PHAsset based code I used in my question (or at least it was't able to in my experience) - even if those files are files the user took with the camera on their own iPhone. So, one solution is to re-save the file in question to a location which is accessible to the Firebase Storage API and then upload the file by passing in that location's URL in to the putFile() method.
You can use this method if you're using the imagePickerController() method:
do {
let documentsURL = FileManager.default().urlsForDirectory(.documentDirectory,
inDomains: .userDomainMask)[0]
let fileURL = try documentsURL.appendingPathComponent("fileName.jpg")
let image = info[UIImagePickerControllerOriginalImage]
try UIImageJPEGRepresentation(image as! UIImage,1.0)?.write(to: fileURL, options: [])
FIRStorage.storage().reference().child("exampleLocation")
.putFile(fileURL, metadata: nil) { (metadata, error) in
if let error = error {
print("Error uploading: \(error.description)")
return
}
}
}
catch {
print("error is ", error)
}
It's possible that our uploader doesn't have the correct permissions to access that file due to the app sandbox (and we're pretty hesitant to grant broad file system access permissions).
I only recommend storing files in Documents/
and tmp/
per https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html
Granted, if it's coming from system resources, we might want to revisit that behavior. Typically I just do (yes, I know it's data
instead of file
and thus will have worse memory behavior):
// pragma mark - UIImagePickerDelegate overrides
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
// Get local image
guard let image: UIImage = info[UIImagePickerControllerOriginalImage] as? UIImage else { return }
let imageData = UIImagePNGRepresentation(image)!
// Get a reference to the location where we'll store our photos
let photosRef = storage.reference().child("chat_photos")
// Get a reference to store the file at chat_photos/<FILENAME>
let photoRef = photosRef.child("\(NSUUID().UUIDString).png")
// Upload file to Firebase Storage
let metadata = FIRStorageMetadata()
metadata.contentType = "image/png"
photoRef.putData(imageData, metadata: metadata).observeStatus(.Success) { (snapshot) in
// When the image has successfully uploaded, we get it's download URL
let text = snapshot.metadata?.downloadURL()?.absoluteString
}
// Clean up picker
dismissViewControllerAnimated(true, completion: nil)
}
@Mike McDonald, thanks for your answer it worked for me. I was having the exact same issue and was able to solve with your suggestions. Here is my code:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
guard let image: UIImage = info[UIImagePickerControllerOriginalImage] as! UIImage else { return }
let profileImageName = "profileImageName.png"
let imageData = UIImagePNGRepresentation(image)!
let filePath = "\(FIRAuth.auth()!.currentUser!.uid)/\(Int(NSDate.timeIntervalSinceReferenceDate() * 1000))"
let photoStorageRef = FIRStorage.storage().reference().child(filePath)
let photoRef = photoStorageRef.child("\(profileImageName)")
let metadata = FIRStorageMetadata()
metadata.contentType = "image/png"
photoRef.putData(imageData, metadata: metadata) { metadata, error in
if let error = error {
print("Error uploading:\(error.localizedDescription)")
return
} else {
guard let downloadURL = metadata!.downloadURL() else { return }
guard let downloadURLString = metadata!.downloadURL()?.absoluteString else { return }
//do what I need to do with downloadURL
//do what I need to do with downloadURLString
}
}
Hope this can help anyone else having the same issue!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With