Firebase Storage Upload Error in Share Extensions - ios

I'm creating an app with App Extension and I'm having trouble uploading files to firebase storage.
I choose a photo that I chose from the Photos application or another application for my own application by pressing the share button.
I am getting the URL of the selected photo in ShareViewController.
if let items = (self.extensionContext?.inputItems.first as? NSExtensionItem)?.attachments {
let contentType = kUTTypeData as String
for item in items {
item.loadItem(forTypeIdentifier: contentType, options: nil) { url, error in
if let path = url as? NSURL {
URLs.append(path.absoluteString!)
}
else {}
}
}
}
I'm trying to upload the URLs I get this way to firebase storage.
let uploadTask = riversRef.putFile(from: URLs[0], metadata: nil) { metadata, error in
guard let metadata = metadata else {
return
}
...
}
There is a problem with the URL of the selected photo but I can't quite understand it. I can get the size, name and other properties of the photo from the URL. I can even copy this photo to another directory with FileManager. I'm getting the URL from FileManager but still getting the same error. But when I try to install I get the following error.
Error Domain=FIRStorageErrorDomain Code=-13000 "An unknown error occurred, please check the server response." UserInfo={bucket=appBucketName, _NSURLErrorFailingURLSessionTaskErrorKey=BackgroundUploadTask <9381D3C6-241C-4737-9589-BA5A7CFAF9E4>.<1>, object=PATH/6B36F026-CD6E-4E00-8A19-C530DC606674.jpg, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"BackgroundUploadTask <9381D3C6-241C-4737-9589-BA5A7CFAF9E4>.<1>"
), NSLocalizedDescription=An unknown error occurred, please check the server response., ResponseErrorDomain=NSURLErrorDomain, ResponseErrorCode=-995}
Solutions I tried;
I will not use putData.
I tried App Groups. I already have the URL of the file. I need to install directly but it doesn't work.
extension FileManager {
func documentsDirectory() -> URL {
let path = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.name")
return path!
}
func uploadPath(srcURL: URL, name: String, completion: #escaping ((_ filePath: URL?) -> Void)) {
do {
let path = documentsDirectory().appendingPathComponent("tempory")
try FileManager.default.createDirectory(atPath: path.relativePath, withIntermediateDirectories: true, attributes: nil)
let fullPath = path.appendingPathComponent(name)
try FileManager.default.copyItem(at: srcURL, to: fullPath)
completion(fullPath)
}
catch {
completion(nil)
}
}
}
Note: I am using Firebase emulator and Xcode simulator. I don't have any problems with the main application.
If there is missing information or incorrect information, please warn, I will correct it. Thank you for your help in advance.

Related

Error uploading video to cloud storage swiftui

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.

Using PHPickerViewController results in a Permission Error

I am trying to use the PHPickerViewController to select images from my photo gallery and seeing the following error.
Could not create a bookmark: NSError: Cocoa 257 "The file couldn’t be
opened because you don’t have permission to view it
I am using Xcode 12.5 on Mac M1 (macOS 11.2.3) And connecting to an iPhone 12 (IOS 14.8).
The code in question appears to throw the above exception in the call to loadFileRepresentation. I have also tried loadInPlaceFileRepresentation and loadObject with similar results.
private func getPhoto(from itemProvider: NSItemProvider) {
print(itemProvider.registeredTypeIdentifiers)
itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier) { url, error in
if let error = error {
print("Encountered Error in loadFileRepresentation \(error.localizedDescription)")
}
if url != nil {
print("Obtained url: \(String(describing: url))")
} else {
print("Could not obtain url")
}
let imageData = try! Data(contentsOf: url!)
DispatchQueue.main.async {
self.parent.mediaItems.append(item: PhotoPickerItem(with: UIImage(data:imageData)!))
}
}
}
I can see that the itemProvider has the following representations.
["public.heic", "public.jpeg"]
and I have tried UTType.jpeg.identifier as well.
Any pointers would be greatly appreciated

Can't Upload Video to Firebase Storage on iOS 13

Works perfectly fine on iOS 12.
Simple boilerplate code:
let storageRef = storage.reference().child("\(profile.studioCode)/\(selected.classId)/\(uploadDate)")
//Upload file and metadata
let uploadTask = storageRef.putFile(from: videoURL, metadata: metadata)
//Listen for state changes and, errors, and completion of the upload
uploadTask.observe(.resume) { (snapshot) in
//upload resumed or started
}
uploadTask.observe(.pause) { (snapshot) in
//upload paused
}
uploadTask.observe(.progress) { (snapshot) in
//upload progress
}
uploadTask.observe(.success) { (snapshot) in
//upload successful
}
uploadTask.observe(.failure) { (snapshot) in
//upload failed
}
Gives me:
Error Domain=FIRStorageErrorDomain Code=-13000 "An unknown error occurred, please check the server response."
I've updated Cocoapods and Firebase to the newest versions, tried allowing arbitrary loads, and tried signing out and back into the app to reset my auth token. In iOS 13 it throws that error immediately on upload, but on iOS 12 it uploads perfectly fine. Any help or insight would be greatly appreciated. Thanks!
I had a similar issue but here is an easy workaround: You need to use '.putData' instead of '.putFile' and specify the MIME type on upload.
let metadata = StorageMetadata()
//specify MIME type
metadata.contentType = "video/quicktime"
//convert video url to data
if let videoData = NSData(contentsOf: videoURL) as Data? {
//use 'putData' instead
let uploadTask = storageRef.putData(videoData, metadata: metadata)
}
How I ended up fixing it:
It turns out that file paths are different in iOS 13 than iOS 12:
iOS12 path:
file:///private/var/mobile/Containers/Data/Application/DF9C58AB-8DCE-401B-B0C9-2CCAC69DC0F9/tmp/12FD0C43-F9A0-4DCB-96C3-18ED83FED424.MOV
iOS13 path:
file:///private/var/mobile/Containers/Data/PluginKitPlugin/5DFD037B-AC84-463B-84BD-D0C1BEC00E4C/tmp/trim.7C8C6CD1-97E7-44D4-9552-431D90B525EA.MOV
Note the extra '.' in the iOS13 path. My solution was to, inside of my imagePickerController didFinishPickingMediaWithInfo function, copy the file into another temp directory, upload it from there, and then delete the copy.
do {
if #available(iOS 13, *) {
//If on iOS13 slice the URL to get the name of the file
let urlString = videoURL.relativeString
let urlSlices = urlString.split(separator: ".")
//Create a temp directory using the file name
let tempDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let targetURL = tempDirectoryURL.appendingPathComponent(String(urlSlices[1])).appendingPathExtension(String(urlSlices[2]))
//Copy the video over
try FileManager.default.copyItem(at: videoURL, to: targetURL)
picker.dismiss(animated: true) {
self.videoRecorded = false
self.showUpload(targetURL)
}
}
else {
//If on iOS12 just use the original URL
picker.dismiss(animated: true) {
self.videoRecorded = false
self.showUpload(videoURL)
}
}
}
catch let error {
//Handle errors
}

Download a pdf from Firebase and store it locally on iOS

I need to download a pdf from the storage and save it locally on an iOS device, so it can be seen in Files.
Here is the code is taken from the docs, which I'm using:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let userID = Auth.auth().currentUser!.uid
print(userID)
// Get a reference to the storage service using the default Firebase App
let storage = Storage.storage()
// Create a storage reference from our storage service
let storageRef = storage.reference()
// Create a reference to the file you want to download
let islandRef = storageRef.child("pdf/sample.pdf")
// Create local filesystem URL
let localURL = URL(string: "pdf/sample.pdf")!
// Download to the local filesystem
let downloadTask = islandRef.write(toFile: localURL) { url, error in
if let error = error {
// Uh-oh, an error occurred!
} else {
// Local file URL for "images/island.jpg" is returned
}
}
}
When I try to run this ViewController, it doesn't crash but throws the following error:
"The file couldn’t be opened because the specified URL type isn’t supported." UserInfo={NSURL=pdf/sample.pdf}
The file in the Firebase Storage is saved in a folder called pdf/sample.pdf. Eventually, I wish to take the reference from the storage and pass it in a RealtimeDatabase, so the user can download it by viewing details about it in a table view.
I think what need to do is to specify in which path to your local filesystem you want to save the downloaded document. So let say you want to use the temporary folder to save your pdf. You can try the following:
let tmporaryDirectoryURL = FileManager.default.temporaryDirectory
let localURL = tmporaryDirectoryURL.appendingPathComponent("sample.pdf")
islandRef.write(toFile: localURL) { url, error in
if let error = error {
print("\(error.localizedDescription)")
} else {
self.presentActivityViewController(withUrl: url)
}
}
Once the file is downloaded in order to save it in the Files app you will need to use UIActivityViewController.
func presentActivityViewController(withUrl url: URL) {
DispatchQueue.main.async {
let activityViewController = UIActivityViewController(activityItems: [url], applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView = self.view
self.present(activityViewController, animated: true, completion: nil)
}
}
I haven't tested it but my assumption is that you get this error because your localURL variable is not a filesystem URL.
Instead of using URL(string: String) you should be using URL(fileURLWithPath: String) when opening files.

Using Firebase Storage's putFile() method is resulting in: The file “fileName” couldn’t be opened error

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!

Resources