Keep Downloaded File (Cache) For The Next Time Application Open - ios

I download external pdf file using this Alamofire way.
The problem is, I would like to keep it for the next time user open the app. So the user does not need to download the pdf again.
I use the following method to download
let destination =
Alamofire.Request.suggestedDownloadDestination(directory: .CachesDirectory,
domain: .UserDomainMask);
Alamofire.download(.GET, urlString, destination: destination)
.progress { bytesRead, totalBytesRead, totalBytesExpectedToRead in
}
.response { request, response, _, error in
print("Downloaded to \(destination(NSURL(string: "")!, response!))");
}
The downloadedFilePath is something like this.
file:///var/mobile/Containers/Data/Application/4957AD15-947A-47D6-A126-EA06A5BCB099/Library/Caches/RewardMe-Presentation-at-NVIDIA-Auditorium.pdf
How do I keep the file for the next time my app launches?
I saved that path into NSUserDefaults the next time the app launches but the file is already gone.

There is a couple of functions add them into you code and call the copyFile where you are showing the path or after that.
func getPath(fileName: String) -> String {
let documentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let fileURL = documentsURL.URLByAppendingPathComponent(fileName)
print("File Path Is : \(fileURL)")
return fileURL.path!
}
func copyFile(fileName: NSString , filePath : NSString) {
let dPath: String = getPath(fileName as String)
let fileManager = NSFileManager.defaultManager()
if !fileManager.fileExistsAtPath(dPath) {
let fromPath : NSURL = NSURL.fileURLWithPath(filePath);
var error : NSError?
do {
try fileManager.copyItemAtPath(fromPath.path!, toPath: dPath)
} catch let error1 as NSError {
error = error1
}
let alert: UIAlertView = UIAlertView()
if (error != nil) {
alert.title = "Error Occured"
alert.message = error?.localizedDescription
} else {
alert.title = "Successfully Copy"
alert.message = "Your File copy successfully"
}
alert.delegate = nil
alert.addButtonWithTitle("Ok")
alert.show()
}
}
copyFile two parameter one is file name for the file you want to save and second is where the file located.
And for checking what to do next time when application open. First get file path and check the file exist or not. If exist the d'not download the file otherwise download file.
let filePath: String = getPath("testFile.pdf")
let fileManager = NSFileManager.defaultManager()
if fileManager.fileExistsAtPath(dPath) {
//Code for using the file data
}
else {
//Download code for the file
}
Hope it helps :)

HTTP already has a caching mechanism, you could consider using it. Don't re-invent the wheel. Here's a way to do it.

Related

iOS: How can app extension copy file to app Documents/ folder?

In the app extension is there a way to get file and copy it to Documents// folder?
I can get file with the code below. But how to copy it? I alway have an error
for item in self.extensionContext!.inputItems as! [NSExtensionItem] {
for provider in item.attachments! as! [NSItemProvider] {
provider.loadItem(forTypeIdentifier: provider.registeredTypeIdentifiers.first! as! String, options: nil, completionHandler: { (fileURL, error) in
if let fileURL = fileURL as? URL {
self.url = fileURL
// self.extensionOpenUrl(App.associatedDomain + fileURL.absoluteString)
}
})
}
}
copy by click:
let fileManager = FileManager.default
let pathForDocumentsDirectory = fileManager.containerURL(forSecurityApplicationGroupIdentifier: App.group)!.path
let fileURL = self.url!
let name = fileURL.lastPathComponent
let copiedPath = pathForDocumentsDirectory
do {
try fileManager.copyItem(atPath: fileURL.absoluteString, toPath: copiedPath)
if fileManager.fileExists(atPath: copiedPath) {
print("fileExists!!!")
}
} catch let error as NSError {
print("error in copyItemAtPath")
print(error.localizedDescription)
}
file url:
file:///var/mobile/Media/PhotoData/OutgoingTemp/3CEC8D4A-9B1B-468B-A919-7C70C9C522B3/IMG_5484.jpg
path to copy:
/private/var/mobile/Containers/Shared/AppGroup/D7D2317B-9C57-424D-9D2F-209C62BBFAE5/IMG_5484.jpg
error:
The file “IMG_5484.jpg” couldn’t be opened because you don’t have permission to view it.
You can't do that. Extensions can communicate with the main app only by leaving/modifying the files in the App Group space (which means also that you must create the App Group first in the developer portal and add proper entitlements).

SSZipArchive "failed to open zip file" -- url.path is not the solution

Edit 2:
I tried Zip from marmelroy (https://github.com/marmelroy/Zip) and it failed on the zip-file created witch ZipArchive too.
Then I created another zip-file with Zip and this one worked fine for unzipping.
There seems to be a problem with ZipArchive for me. I will use Zip instead and thats it for me ...
Thx for the answers !!
End edit 2.
I need to unzip certain files so I manually installed SSZipArchive.
Copied all 3 folders (SSZipArchive, minizip, aes) to project, added #import "ZipArchive.h" in my bridging.h and all builds nicely.
Edit:
Used Carthage as recommended, but same behavior.
End edit.
I use Xcode 8 / Swift 3
After a few tests with no unzipping any file, I created my own zip using SSZipArchive.
let file = "file.txt"
let text = "some text" //just a text
let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
let path = dir?.appendingPathComponent(file)
//writing
do {
try text.write(to: path!, atomically: false, encoding: String.Encoding.utf8)
}
catch {
print("Failed writing")
}
Here I print() the Documentsdirectory: ["file.txt"]
let zipPath = tempZipPath() //tempZipPath is taken from the SSZipArchiveExample except it uses DocumentDirectory instead of Cache...
print("zipPath: \(zipPath)")
print zipPath: /var/mobile/Containers/Data/Application/EB439A61-07B9-4910-BF28-03E85C50B292/Documents/93428A1B-E5B6-434F-B049-632B7519B126.zip
let success = SSZipArchive.createZipFile(atPath: zipPath, withContentsOfDirectory: (dir?.absoluteString)!)
if success {
print("zipped")
} else {
print(" NOT zipped")
}
Again the Documentsdirectories entries: ["93428A1B-E5B6-434F-B049-632B7519B126.zip", "file.txt"]
// this is again taken from the original Example
guard let unzipPath = tempUnzipPath() else {
return
}
print("unzipPath: \(unzipPath)")
print unzipPath: /var/mobile/Containers/Data/Application/EB439A61-07B9-4910-BF28-03E85C50B292/Documents/E4FC7DE6-F21B-46D8-9953-DCBF86E2268E
Reading the entries of this new directory: []
let filePath = zipPath
var fileSize : UInt64 = 0
do {
let attr : NSDictionary? = try FileManager.default.attributesOfItem(atPath: filePath) as NSDictionary?
if let _attr = attr {
fileSize = _attr.fileSize();
print("fileSize: \(fileSize)")
}
} catch {
print("Error: \(error)")
}
this writes 22. I also tried to read the zip-file which works fine
From this part on I was desperate what to do
let url = URL(fileURLWithPath: zipPath)
print("url: \(url)")
print("url.path: \(url.path)")
print("url.absoluteString: \(url.absoluteString)")
print("url.absoluteURL: \(url.absoluteURL)")
print("url.absoluteURL.absoluteString: \(url.absoluteURL.absoluteString)")
The output of these lines look all good for me:
url:
file:///var/mobile/Containers/Data/Application/EB439A61-07B9-4910-BF28-03E85C50B292/Documents/93428A1B-E5B6-434F-B049-632B7519B126.zip
url.path:
/var/mobile/Containers/Data/Application/EB439A61-07B9-4910-BF28-03E85C50B292/Documents/93428A1B-E5B6-434F-B049-632B7519B126.zip
url.absoluteString:
file:///var/mobile/Containers/Data/Application/EB439A61-07B9-4910-BF28-03E85C50B292/Documents/93428A1B-E5B6-434F-B049-632B7519B126.zip
url.absoluteURL:
file:///var/mobile/Containers/Data/Application/EB439A61-07B9-4910-BF28-03E85C50B292/Documents/93428A1B-E5B6-434F-B049-632B7519B126.zip
url.absoluteURL.absoluteString:
file:///var/mobile/Containers/Data/Application/EB439A61-07B9-4910-BF28-03E85C50B292/Documents/93428A1B-E5B6-434F-B049-632B7519B126.zip
And then I tried them all (Strings of course. No url allowed)
var success2 = SSZipArchive.unzipFile(atPath: zipPath, toDestination: unzipPath)
if !success2 {
print("zipPath")
}
success2 = SSZipArchive.unzipFile(atPath: url.path, toDestination: unzipPath)
if !success2 {
print("url.path")
}
success2 = SSZipArchive.unzipFile(atPath: url.absoluteString, toDestination: unzipPath)
if !success2 {
print("url.absoluteString")
}
success2 = SSZipArchive.unzipFile(atPath: url.absoluteURL.path, toDestination: unzipPath)
if !success2 {
print("url.absoluteURL.path")
}
And it prints every line, so they all failed. At the end here comes the "long" way with unipFileAtPath. I tried this one too with zipPath, ...
All the same results.
do {
success2 = try SSZipArchive.unzipFileAtPath(url.path, toDestination: unzipPath, overwrite: true, password: nil, delegate: nil)
if !success2 {
return
}
} catch {
print("error \(error)")
print("error \(error.localizedDescription)")
}
error Error Domain=SSZipArchiveErrorDomain Code=-1 "failed to open zip
file" UserInfo={NSLocalizedDescription=failed to open zip file} error
failed to open zip file
Here the to func to get the path-strings. btw. I modified tempZipPath so returns an URL or an URL.path
but hey: I was desperate
func tempZipPath() -> String {
var path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
path += "/\(UUID().uuidString).zip"
return path
}
func tempUnzipPath() -> String? {
var path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
path += "/\(UUID().uuidString)"
let url = URL(fileURLWithPath: path)
do {
try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
} catch {
return nil
}
return url.path
}
Any suggestions? Is there something to consider manually installing SSZipArchive?
The tip "use .path instead of .absoluteString" didn't work for me as u can see above.
a desperate tartsigam
I had the problem, too. If you use url.path instead of url.absolutString, it works.
Thanks to vadian for the hint!
Before zip don't extract file and return false.
After put this in Build Settings / Apple CLang Prepocessing / Preprocessor Macros Debug e Release works here
GCC_PREPROCESSOR_DEFINITIONS: HAVE_INTTYPES_H HAVE_PKCRYPT HAVE_STDINT_H HAVE_WZAES HAVE_ZLIB MZ_ZIP_NO_SIGNING $(inherited)
In my case, using ObjC and manual installation, I forgot to Add the following GCC_PREPROCESSOR_DEFINITIONS:
$(inherited)
HAVE_INTTYPES_H
HAVE_PKCRYPT
HAVE_STDINT_H
HAVE_WZAES
HAVE_ZLIB
After adding these GCC_PREPROCESSOR_DEFINITIONS it worked as expected.

Why are deleted files coming back after a new write to file? Swift 2.0

I am writing an app in swift that logs sensor data to a txt file. When I have an event occur that needs to be logged I create the filename
func createNewLogFile (){
// Create a new file name
currentFileName = "log\(NSDate()).txt"
//get the path
let paths = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
//create the file
_ = paths[0].URLByAppendingPathComponent(currentFileName)
}
After the file is created I write data to the new file like this:
func writeData (data: String){
// get the path to document directory
let paths = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
let filePath = paths[0].URLByAppendingPathComponent(currentFileName)
//get the data to be logged
let stringLocation = data
let stringData = stringLocation.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
//look to see if the file exist
if NSFileManager.defaultManager().fileExistsAtPath(filePath.path!) {
do {
//seek to the end of the file to append data
let fileHandle = try NSFileHandle(forWritingToURL: filePath)
fileHandle.seekToEndOfFile()
fileHandle.writeData(stringData)
fileHandle.closeFile()
} catch {
print("Can't open fileHandle \(error)")
}
} else {
do {
// write to new file
try stringData.writeToURL(filePath, options: .DataWritingAtomic)
} catch {
print("Can't write to new file \(error)")
}
}
}
When I delete the files (from a different ViewController or the same, I tried both)
I am calling this DeleteAllFiles
func deleteAllFiles (Extension: String){
let dirs = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
let dir = dirs[0]
do {
let fileList = try NSFileManager.defaultManager().contentsOfDirectoryAtURL(dir, includingPropertiesForKeys: nil, options: NSDirectoryEnumerationOptions())
//return fileList as [String]
for elements in fileList{
do{
try NSFileManager.defaultManager().removeItemAtURL(elements)
print("old Files has been removed")
} catch let error as NSError {
print(error.localizedDescription)
}
}
}catch let error as NSError {
print(error.localizedDescription)
}
}
I then refresh the list and the files seem to be gone.(even when I go back and forth between views) However, when I write a new file and refresh the list the files are back with the new file.
This even happens when I delete them from iTunes using the shared files feature.
Any ideas on why this is happening? I am not getting any helpful error messages.
I found the fix for the problem.
When I was creating the file I actually only meant to create the file name. There was no reason to actually create the file at this time. I am creating the actual file when I write to it.
func createNewLogFile (){
// Create a new file name
currentFileName = "log\(NSDate()).txt"
//Removed creating actual file code
}

Having trouble saving a file in a folder inside Document directory in Swift 2

I am trying to save a file inside a subfolder in Documents directory but it won't save. I can't seem to find what's wrong. Here is what I've tried:
if let audioUrl = NSURL(string: "http://pillar.foundationu.com/wp-content/plugins/pillar-data-sync/php/htmlBreakdownResult.json") {
let documentsUrl = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
do {
let directoryContents = try NSFileManager.defaultManager().contentsOfDirectoryAtURL(documentsUrl, includingPropertiesForKeys: nil, options: NSDirectoryEnumerationOptions())
print(directoryContents[0].path!)
if NSFileManager().fileExistsAtPath(String(audioUrl.path!)) {
print("The file already exists at path")
} else {
// if the file doesn't exist
// just download the data from your url
if let myAudioDataFromUrl = NSData(contentsOfURL: audioUrl){
// after downloading your data you need to save it to your destination url
if myAudioDataFromUrl.writeToURL(NSURL(fileURLWithPath: directoryContents[0].path!), atomically: true) {
print("file saved")
} else {
print("error saving file")
}
}
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
Here is where I want to save the file:
/Users/rendell/Library/Developer/CoreSimulator/Devices/5A052CC5-FD34-44FD-B060-24D6F1970860/data/Containers/Data/Application/37753B0B-FAB0-478D-A7F8-98E3039D07DD/Documents/MyFolder2
But it keeps on giving me "error saving file".
First of all, use always writeToURL:options:error to get a (more) descriptive error message.
The issue is quite simple: You forgot to provide a file name.
Technically you're going to overwrite an existing folder with data. That's not possible.

How to properly move In App Purchase download files from cache in iOS?

I am trying to set up an app with an In App Purchase that downloads content for 12 levels of a game when that respective pack is purchased.
I am stuck on how to properly move the downloaded images from the cache folder to the Documents folder. Here is my code so far:
func processDownload(sender: NSURL) {
//Convert URL to String, suitable for NSFileManager
var path:String = sender.path!
path = path.stringByAppendingPathComponent("Contents")
//Makes an NSArray with all of the downloaded files
let fileManager = NSFileManager.defaultManager()
var files: NSArray!
do {
files = try fileManager.contentsOfDirectoryAtPath(path)
} catch let err as NSError {
print("Error finding zip URL", err.localizedDescription)
}
//For each file, move it to Library
for file in files {
let pathSource: String = path.stringByAppendingPathComponent(file as! String)
let pathDestination: String = NSSearchPathForDirectoriesInDomains(.LibraryDirectory, .UserDomainMask, true)[0]
//Remove destination files b/c not allowed to overwrite
do {
try fileManager.removeItemAtPath(pathDestination)
}catch let err as NSError {
print("Could not remove file", err.localizedDescription)
}
//Move file
do {
try fileManager.moveItemAtPath(pathSource, toPath: pathDestination)
print("File", file, "Moved")
}catch let err as NSError {
print("Couldn't move file", err.localizedDescription)
}
}
}
Everything actually works just fine except for the errors that are printing from the two do statements. When trying to remove any existing files of the same name in the first do block, I get the following error:
Could not remove file “Library” couldn’t be removed because you don’t have permission to access it.
This subsequently causes the next error from the next do statement to print because the original could not be removed.
Any ideas of why this is happening and how I can properly save the downloaded files elsewhere? Thanks.
I've found a proper working solution. This code will move all of the items in the downloaded zip folder to the Library directory.
func processDownload(sender: NSURL) {
//Convert URL to String, suitable for NSFileManager
var path: String = sender.path!
path = path.stringByAppendingPathComponent("Contents")
//Makes an NSArray with all of the downloaded files
let fileManager = NSFileManager.defaultManager()
var files: NSArray!
do {
files = try fileManager.contentsOfDirectoryAtPath(path)
} catch let err as NSError {
print("Error finding zip URL", err.localizedDescription)
}
//For each file, move it to Library
for file in files {
let currentPath: String = path.stringByAppendingPathComponent(file as! String)
var pathDestination: String = NSSearchPathForDirectoriesInDomains(.LibraryDirectory, .UserDomainMask, true)[0]
pathDestination = pathDestination.stringByAppendingPathComponent(file as! String)
//Move file
do {
try fileManager.moveItemAtPath(currentPath, toPath: pathDestination)
print("File", file, "Moved")
}catch let err as NSError {
print("Couldn't move file", err.localizedDescription)
}
}
}
I can now make SKTextures in SpriteKit with these files like so:
var rippleTex = SKTexture(image: UIImage(contentsOfFile: NSSearchPathForDirectoriesInDomains(.LibraryDirectory, .UserDomainMask, true)[0].stringByAppendingPathComponent("P06_ripple.png"))!)

Resources