I have the following code. My goal is to decode the data once the file has been downloaded to the device. I used fileExists to check if the file existed on iCloud. And then startDownloadingUbiquitousItem to download it. But I can't figure out how to tell if it has been downloaded. May I ask if there is a way to tell its downloaded? Like a completion handler or notification?
if paperyCloudURL != nil, FileManager.default.fileExists(atPath: paperyCloudURL!.path, isDirectory: nil) {
try? FileManager.default.startDownloadingUbiquitousItem(at: paperyCloudURL!)
//TODO: Should have check if the file exist before load
let data = try Data(contentsOf: paperyCloudURL!)
dataModel = try! decoder.decode(DataModel.self, from: data)
}
You need to test the file NSMetadataQuery object key NSMetadataUbiquitousItemDownloadingStatusKey is set to NSMetadataUbiquitousItemDownloadingStatusCurrent.
Related
I'm basically trying to save an audio file to an iPhone device, specifically in the Files app.
This is the code I'm using which works in the iOS Simulator:
if let audioUrl = URL(string: "https://file-examples.com/wp-content/uploads/2017/11/file_example_MP3_700KB.mp3") {
// then lets create your document folder url
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
// lets create your destination file url
let destinationUrl = documentsDirectoryURL.appendingPathComponent(audioUrl.lastPathComponent)
print(destinationUrl)
// to check if it exists before downloading it
if FileManager.default.fileExists(atPath: destinationUrl.path) {
print("The file already exists at path", destinationUrl)
// if the file doesn't exist
} else {
// you can use NSURLSession.sharedSession to download the data asynchronously
URLSession.shared.downloadTask(with: audioUrl) { location, response, error in
guard let location = location, error == nil else { return }
do {
// after downloading your file you need to move it to your destination url
try FileManager.default.moveItem(at: location, to: destinationUrl)
print("File moved to documents folder", destinationUrl)
} catch {
print(error)
}
}.resume()
}
}
this is the result in the simulator:
2022-04-08 15:48:17.605964+0200 TunnelPlay[3977:122650] [boringssl] boringssl_metrics_log_metric_block_invoke(153) Failed to log metrics
File moved to documents folder file:///Users/panashemuzamhindo/Library/Developer/CoreSimulator/Devices/A7F7DD88-1E0C-45CD-9783-F46E6644F98C/data/Containers/Data/Application/EDE8B3CC-C290-4369-8B88-4AE1717B9DB8/Documents/1645329769Sengkhathele(featit.caramel).mp3
Main Problem: When I try run this section in TestFlight, the app runs the save process but theres nothing in Files, maybe I'm looking for it in the wrong location? or I need some permissions?
Desired Outcome: I want to see the downloaded MP3 in the iPhone Files app.
And I did try to change the scheme to Release instead of Debug, but it still doesn't save the file.
If you want to be able to access the files in the iOS Files app, make sure to also enable LSSupportsOpeningDocumentsInPlace (in addition to enabling UIFileSharingEnabled)
LSSupportsOpeningDocumentsInPlace
A Boolean value indicating whether the app may open the original document from a file provider, rather than a copy of the document.
UIFileSharingEnabled
A Boolean value indicating whether the app shares files.
hope you are doing good in development. I have a question regarding Zipping currently i am using Zip framework which I am using for zip the all captured image in device but the problem here is I do not want to save the Zip file in document directory instead I wanna save this memory itself. I am struggling since last week please let me know how can we achieve the zipping without saving it in local directory filepath
Also when I captured the image successfully I saved it to local directory using
let documentsDirectory = FileManager.default.urls(for:
.documentDirectory, in: .userDomainMask).first!
let fileName = "image.jpg"
let fileURL = documentsDirectory.appendingPathComponent(fileName)
if let data = UIImageJPEGRepresentation(image, 1.0),
!FileManager.default.fileExists(atPath: fileURL.path) {
do {
// writes the image data to disk
try data.write(to: fileURL)
print("file saved")
} catch {
print("error saving file:", error)
}
}
After when I am trying to send the image before our server I want to make it all one file so I have implemented the Zip (framework)
Here filpathArray meant all captured image in local path
do {
var urls = [URL]()
for i in 0..<(self.filePathArray.count)
{
urls.append(self.filePathArray[i] as! URL)
}
if self.filePathArray.count > 0 {
let zipFiles = try Zip.quickZipFiles(urls, fileName: "AllFiles")
}
}
Here zipping is done successfully but it saved in local path so when using app container I can able to see the images, I do not want to see the images in device like apple sandbox or Xcode container itself
I want to make zipping on the flow like without saving it document directory, Thanks in advance.
I'm trying to download a youtube video on the phone so the user can later play it offline. I hooked a button to where the user can download. The code of how I'm currently downloading the video is here below.
#objc func downloadSelectedVideo() {
if let audioUrl = URL(string: "http://freetone.org/ring/stan/iPhone_5-Alarm.mp3") {
// create your document folder url
let documentsUrl = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
// your destination file url
let destination = documentsUrl.appendingPathComponent(audioUrl.lastPathComponent)
print(destination)
// check if it exists before downloading it
if FileManager().fileExists(atPath: destination.path) {
print("The file already exists at path")
} else {
// if the file doesn't exist
// just download the data from your url
URLSession.shared.downloadTask(with: audioUrl, completionHandler: { (location, response, error) in
// after downloading your data you need to save it to your destination url
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("audio"),
let location = location, error == nil
else { return }
do {
try FileManager.default.moveItem(at: location, to: destination)
print("file saved")
} catch {
print(error)
}
}).resume()
}
}
}
as you can see I have hooked up the URL to a free music which is in mp3 and it works fine I can download the music and everything works just fine, however when I try to hook up a YouTube video then it never gets to the print statement file saved I tried this as the URL if let audioUrl = URL(string: "https://www.youtube.com/watch?v=3WSgJCYIewM")
but the print statement file saved never ran, but when I tried with the other I mentioned earlier it print file saved.
What URL should use to download the youtube videos, and do I have to use an mp3 or mp4 source to download the videos. I'm trying not to use any third-party sites if you can come up with any solution it would be great and helpful. Thanks
YouTube spells this out pretty specifically that you cannot do this.
YouTube API Services - Developer Policies
Found this under E. Handling YouTube Data and Content
You and your API Clients must not, and must not encourage, enable, or
require others to:
download, import, backup, cache, or store copies of YouTube
audiovisual content without YouTube's prior written approval,
IANAL, but I'd rather not go up against their legal team.
YouTube does not provide a simple URL that taps into the video or audio directly. Instead, you would have to extract thier link using some algorithm. If you'd like to achieve that I would recommend you use XCDYouTubeKit as it is well maintained and easy to use. However, If you'd like a ready made app, I have developed an open source application - YouTag - that you can simply install on your iOS device and use directly without having to go through developing one.
In AppDelegate.swift, on first launch, the intent is to place some sample docs in the local Documents folder, or in the iCloud Documents folder if iCloud is enabled.
var templates = NSBundle.mainBundle().pathsForResourcesOfType(AppDelegate.myExtension, inDirectory: "Templates")
dispatch_async(appDelegateQueue) {
self.ubiquityURL = NSFileManager.defaultManager().URLForUbiquityContainerIdentifier(nil)
if self.ubiquityURL != nil && templates.count != 0 {
// Move sample documents from Templates to iCloud directory on initial launch
for template in templates {
let tempurl = NSURL(fileURLWithPath: template)
let title = tempurl.URLByDeletingPathExtension?.lastPathComponent
let ubiquitousDestinationURL = self.ubiquityURL?.URLByAppendingPathComponent(title!).URLByAppendingPathExtension(AppDelegate.myExtension)
// let exists = NSFileManager().isUbiquitousItemAtURL(ubiquitousDestinationURL!)
do {
try NSFileManager.defaultManager().setUbiquitous(true, itemAtURL: tempurl, destinationURL: ubiquitousDestinationURL!)
}
catch let error as NSError {
print("Failed to move file \(title!) to iCloud: \(error)")
}
}
}
return
}
Before running this, I delete the app from the device and make sure no doc of that name is in iCloud. On first launch, without iCloud, the sample docs copy properly into the local Documents folder. With iCloud, this code runs, and the setUbiquitous call results in an error that says the file already exists. The commented call to isUbiquitousItemAtURL also returns true.
What might be making these calls register that a file exists that I'm pretty sure doesn't? Thank you!
The file already exists, so just replace it
The primary solution...in all the trial and error, I'd forgotten to put "Documents" back in the url. Should be:
let ubiquitousDestinationURL = self.ubiquityURL?.URLByAppendingPathComponent("Documents").URLByAppendingPathComponent(title!).URLByAppendingPathExtension(AppDelegate.myExtension)
Without that, wrote the file to the wrong directory, and so I couldn't see it by normal means.
I was wondering, if there is a different and faster solution to the following problem. I am downloading a file with NSURLSession. By default (I guess?) the downloaded file is stored in the tmp folder. Then I need to copy this file to the cache folder. At the moment I am using this code for my approach (in the didFinishDownloading function)
if let fileData = NSData(contentsOfURL: sourceUrl) {
fileData.writeToURL(destinationURL, atomically: true) // true
print(destinationURL.path!)
}
However, as my file is pretty large, this takes a while.
Is there a different option on copying this file to the cache folder?
Or is it possible to download a file directly to the Cache folder using the NSURLSession?
Instead of copying the file you can simply move it to the
desired location:
do {
try NSFileManager.defaultManager().moveItemAtURL(sourceURL, toURL: destinationURL)
} catch let err as NSError {
print(err.localizedDescription)
}
This would be much faster because only directory entries in the
file system are modified, but no data is actually copied.
Swift 3 update:
do {
try FileManager.default.moveItem(at: sourceURL, to: destinationURL)
} catch {
print(error.localizedDescription)
}