Firebase Storage download to local file error - ios

I'm trying to download the image f5bd8360.jpeg from my Firebase Storage.When I download this image to memory using dataWithMaxSize:completion, I'm able to download it.
My problem comes when I try to download the image to a local file using the writeToFile: instance method. I'm getting the following error:
Optional(Error Domain=FIRStorageErrorDomain Code=-13000 "An unknown
error occurred, please check the server response."
UserInfo={object=images/f5bd8360.jpeg,
bucket=fir-test-3d9a6.appspot.com, NSLocalizedDescription=An unknown
error occurred, please check the server response.,
ResponseErrorDomain=NSCocoaErrorDomain, NSFilePath=/Documents/images,
NSUnderlyingError=0x1700562c0 {Error Domain=NSPOSIXErrorDomain Code=1
"Operation not permitted"}, ResponseErrorCode=513}"
Here is a snippet of my Swift code:
#IBAction func buttonClicked(_ sender: UIButton) {
// Get a reference to the storage service, using the default Firebase App
let storage = FIRStorage.storage()
// Get reference to the image on Firebase Storage
let imageRef = storage.reference(forURL: "gs://fir-test-3d9a6.appspot.com/images/f5bd8360.jpeg")
// Create local filesystem URL
let localURL: URL! = URL(string: "file:///Documents/images/f5bd8360.jpeg")
// Download to the local filesystem
let downloadTask = imageRef.write(toFile: localURL) { (URL, error) -> Void in
if (error != nil) {
print("Uh-oh, an error occurred!")
print(error)
} else {
print("Local file URL is returned")
}
}
}
I found another question with the same error I'm getting but it was never answered in full. I think the proposal is right. I don't have permissions to write in the file. However, I don't know how gain permissions. Any ideas?

The problem is that at the moment when you write this line:
let downloadTask = imageRef.write(toFile: localURL) { (URL, error) -> Void in
etc.
you don't yet have permission to write to that (localURL) location. To get the permission you need to write the following code before trying to write anything to localURL
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let localURL = documentsURL.appendingPathComponent("filename")
By doing it you will write the file into the following path on your device (if you are testing on the real device):
file:///var/mobile/Containers/Data/Application/XXXXXXXetc.etc./Documents/filename
If you are testing on the simulator, the path will obviously be somewhere on the computer.

Related

Swift: Uploading a file to Firebase Storage from a Share Extension

I am trying to upload an image to firebase storage from a share extension in iOS, I have authed and am communicating with the database but when I attempt to upload the file it fails straight away.
I have made sure that the code that I am using works by using it in my main app. I have also made sure that the file is being saved in the file manager prior to being uploaded correctly.
Here is the code for saving the file prior to the upload:
if let data = downsizeImage(image: image).jpegData(compressionQuality: 0.2) {
let fileManager = FileManager.default
let url = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.com.<DOMAIN>.imageShare")?.appendingPathComponent("ImageToSend.jpg")
do {
try data.write(to: url!)
}
catch {
print(error.localizedDescription)
}
}
Here is the code for the upload task:
let storageRef: StorageReference = Storage.storage().reference().child(storageLocation).child(UUID().uuidString)
var completed = false
var mediaUploadTask: StorageUploadTask?
let mediaTimeoutTask = DispatchWorkItem{ () in
if !completed {
mediaUploadTask?.cancel()
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + 30, execute: mediaTimeoutTask)
mediaUploadTask = storageRef.putFile(from: mediaUrl, metadata: nil) {(metadata, error) in
completed = true
...
}
What should happen is the image is successfully uploaded and the function would continue as normal. What actually happens is the upload fails nearly straight away. Here is the error returned:
Printing description of error:
▿ Optional<Error>
- some : Error Domain=FIRStorageErrorDomain Code=-13000 "An unknown error occurred, please check the server response."
UserInfo={bucket=link-ages-55880.appspot.com,
_NSURLErrorFailingURLSessionTaskErrorKey=BackgroundUploadTask <AC5EADEA-6257-4C32-9454-17626156AA15>.<1>,
object=media/4qnjSBKysi79uCR3cTzf/04D22317-D2C0-4A5C-B032-4F37DB2C8F7A,
_NSURLErrorRelatedURLSessionTaskErrorKey=(
"BackgroundUploadTask <AC5EADEA-6257-4C32-9454-17626156AA15>.<1>"
),
NSLocalizedDescription=An unknown error occurred, please check the server response.,
ResponseErrorDomain=NSURLErrorDomain, ResponseErrorCode=-995}
If anyone has any idea what the problem might be, your ideas would be greatly appreciated. Thanks.
Here is a screenshot of the debugger:
I have found out what the problem was. Due to the way that iOS sandboxing works, calling:
storageRef.putFile(from: mediaUrl, metadata: nil, completion: {(metadata, error) in})
fails. More info Here: Original Answer.
Instead calling:
storageRef.putData(Data, metadata: nil, completion: {(metadata, error) in})
worked as intended.

i have an issue on the file System on the actual device

my problem is when i try to copy images from the photo library to the filesystem i get the error the error is
(Error Domain=NSCocoaErrorDomain Code=257 "The file “IMG_0926.JPG”
couldn’t be opened because you don’t have permission to view it."
UserInfo={NSFilePath=/var/mobile/Media/DCIM/100APPLE/IMG_0926.JPG,
NSUnderlyingError=0x15649630 {Error Domain=NSPOSIXErrorDomain Code=1
"Operation not permitted"}})
my code is :
let fileManager = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let document = fileManager[0]
var i = 0
for asset in arrayOfAssets {
let filePath = document.appendingPathComponent("image\(arrayOfAssets.count + i).png")
i += 1
PHImageManager.default().requestImageData(for: asset, options: nil) { (data, nil, _ , info) in
let url = info?["PHImageFileURLKey"] as! NSURL
do {
try FileManager.default.copyItem(at: url as URL, to: filePath)
}catch {
print(error)
}
// print(filePath)
}
}
please if anyone can help me
thanks all
It sounds like you're trying to open a file located here : NSFilePath=/var/mobile/Media/DCIM/100APPLE/IMG_0926.JPG
By default access to this directory is not permitted, you can only access files located in the document directory, for security reasons.
I don't find where this URL comes from in your code, but according to the NSError you are trying to access an image outside the permitted area of the file system.
Please check the permission option in plist for Photos Library in iOS 11.
Also you can save data in TEMP directory and fetch it when needed and after use
clean data in TEMP directory.

Error when downloading from Firebase storage

I am trying to get basic upload/download working with the new Firebase storage. Uploading worked fine but I am unable to download the file to the device. Can someone please shed some light on what I am doing wrong. Thanks!
func downloadAudio() {
let storageRef = FIRStorage.storage().reference()
let pathReference = storageRef.child("testAudio/audio_test.m4a")
let localURL = getDocumentsDirectory().URLByAppendingPathComponent("audio_test2.m4a")
let downloadTask = pathReference.writeToFile(localURL) { (URL, error) -> Void in
if (error != nil) {
print("ERROR - ", error.debugDescription)
} else {
print("SUCCESS - ", URL)
}
}
}
PRINTS:
ERROR - Optional(Error Domain=FIRStorageErrorDomain Code=-13000 "An unknown error occurred, please check the server response." UserInfo={ResponseErrorDomain=NSCocoaErrorDomain, object=testAudio/audio_test.m4a, NSURL=/Users/Ben/Library/Developer/CoreSimulator/Devices/02AF50F2-E9BE-4EED-A3BE-485D63264731/data/Containers/Data/Application/31BDED56-0135-4E70-943E-F897080768D6/Documents/, bucket=mydevslopesapp.appspot.com, ResponseErrorCode=518, NSLocalizedDescription=An unknown error occurred, please check the server response.})
This is not a storage error, it's actually an issue with the file you're attempting to write to.
Looks like URLByAppengingString should be fileURLWithPath to get a file system URL (per NSFileManager creating directory error 518 NSFileWriteUnsupportedSchemeError).
Long term we need to fish this out and serve it as a "see relevant error" rather than "read network response."

FireBase Storage Download Error Domain=FIRStorageErrorDomain Code=-13000

I'm Currently trying to use the quick start examples for firebase storage from github. Where you simply upload an image and then download it to a another view once that view is loaded. I can upload images to storage fine but when I try to download the images this error occurs.
Error Domain=FIRStorageErrorDomain Code=-13000 "An unknown error occurred, >please check the server response." UserInfo={bucket=****.appspot.com, >object=379f921d-a0bb-44b5-b04e-f21cc7953848/485423329797/IMG_0003.JPG, ResponseErrorDomain=NSCocoaErrorDomain, NSDestinationFilePath=/file:/Users/mark******/Library/Developer/CoreSim>ulator/Devices/B600E8B9-95ED-4963-8282-9CDD43B7C25D/data/Containers/Data/Application/8FFB7EB0-0AFD-4E10-AAB6-D7340F8E3DDB/Documents/myimage.jpg, NSLocalizedDescription=An unknown error occurred, please check the server response., NSUserStringVariant=(
Move
), NSSourceFilePathErrorKey=/Users/mark******/Library/Developer/CoreSimula>tor/Devices/B600E8B9-95ED-4963-8282->9CDD43B7C25D/data/Containers/Data/Application/8FFB7EB0-0AFD-4E10-AAB6->D7340F8E3DDB/tmp/CFNetworkDownload_5ZmlMp.tmp, NSFilePath=/Users/mark******/Library/Developer/CoreSimulator/Devices/B6>00E8B9-95ED-4963-8282->9CDD43B7C25D/data/Containers/Data/Application/8FFB7EB0-0AFD-4E10-AAB6->D7340F8E3DDB/tmp/CFNetworkDownload_5ZmlMp.tmp, NSUnderlyingError=0x7f8036a682d0 {Error Domain=NSPOSIXErrorDomain Code=2 >"No such file or directory"}, ResponseErrorCode=4}
I've checked the paths on the Firebase Storage side of things and the file paths are correct, it just can't seem to retrieve the image.
The code to download the image is in the viewdidload() func of the download file
override func viewDidLoad() {
super.viewDidLoad()
storageRef = FIRStorage.storage().reference()
let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory,
NSSearchPathDomainMask.UserDomainMask, true)
let documentsDirectory = paths[0]
let filePath = "file:\(documentsDirectory)/myimage.jpg"
let storagePath = NSUserDefaults.standardUserDefaults().objectForKey("storagePath") as! String
print("---------------")
print(filePath)
print("---------------")
print(storagePath)
// [START downloadimage]
storageRef.child(storagePath).writeToFile(NSURL.fileURLWithPath(filePath),
completion: { (url, error) in
if let error = error {
print("Error downloading:\(error)")
self.statusTextView.text = "Download Failed"
return
}
self.statusTextView.text = "Download Succeeded!"
self.imageView.image = UIImage.init(contentsOfFile: filePath)
})
// [END downloadimage]
}
}
Looks like the issue here is actually your download file path isn't correct (The error being thrown is actually an NSCocoaErrorDomain rather than a networking issue--it looks like our error message is too specific to the network).
The main issue I see is that your file path looks like /file:/Users/... while I believe that file URLs are supposed to look like file:///Users/...
I typically create local files like so like so:
NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory()];
NSURL *fileURL = [[tmpDirURL URLByAppendingPathComponent:#"hello"] URLByAppendingPathExtension:#"txt"];
You can also use NSHomeDirectoryForUser to get the base directory for the user.

Swift: downloadTaskWithURL sometimes "succeeds" with non-nil location even though file does not exist

The downloadTaskWithURL function sometimes returns a non-nil location for a file that does not exist.
There is no file at http://192.168.0.102:3000/p/1461224691.mp4 in the test environment.
Most of the time, invoking downloadTaskWithURL on this URL results in the expected error message:
Error downloading message during network operation. Download URL:
http://192.168.0.102:3000/p/1461224691.mp4. Location: nil. Error:
Optional(Error Domain=NSURLErrorDomain Code=-1100 "The requested URL
was not found on this server." UserInfo=0x17547b640
{NSErrorFailingURLKey=http://192.168.0.102:3000/p/1461224691.mp4,
NSLocalizedDescription=The requested URL was not found on this
server.,
NSErrorFailingURLStringKey=http://192.168.0.102:3000/p/1461224691.mp4})
Occasionally, and in a non-deterministic way, downloadTaskWithURL believes the file exists and writes something to the location variable. As a result, the guard condition does not fail, and the code continues to execute ... which it should not.
The permanent file created by fileManager.moveItemAtURL(location!, toURL: fileURL) is only 1 byte, confirming that the network file never existed in the first place.
Why does downloadTaskWithURL behave like this?
func download() {
// Verify <networkURL>
guard let downloadURL = NSURL(string: networkURL) where !networkURL.isEmpty else {
print("Error downloading message: invalid download URL. URL: \(networkURL)")
return
}
// Generate filename for storing locally
let suffix = (networkURL as NSString).pathExtension
let localFilename = getUniqueFilename("." + suffix)
// Create download request
let task = NSURLSession.sharedSession().downloadTaskWithURL(downloadURL) { location, response, error in
guard location != nil && error == nil else {
print("Error downloading message during network operation. Download URL: \(downloadURL). Location: \(location). Error: \(error)")
return
}
// If here, no errors so save message to permanent location
let fileManager = NSFileManager.defaultManager()
do {
let documents = try fileManager.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
let fileURL = documents.URLByAppendingPathComponent(localFilename)
try fileManager.moveItemAtURL(location!, toURL: fileURL)
self.doFileDownloaded(fileURL, localFilename: localFilename)
print("Downloaded file # \(localFilename). Download URL: \(downloadURL)")
} catch {
print("Error downloading message during save operation. Network URL: \(self.networkURL). Filename: \(localFilename). Error: \(error)")
}
}
// Start download
print("Starting download # \(downloadURL)")
task.resume()
}
Just to clarify, the server is returning a 404, but the download task is returning a basically-empty file? And you're certain that the server actually returned an error code (by verifying the server logs)?
Either way, I would suggest checking the status code in the response object. If it isn't a 200, then the download task probably just downloaded the response body of an error page. Or, if the status code is 0, the connection timed out. Either way, treat it as a failure.
You might also try forcing this to all happen on a single thread and see if the nondeterminism goes away.

Resources