How to Upload NSDictionary in Memory to Dropbox, IOS - ios

I have an xml string that I want to upload as a .plist to a dropbox folder.
Currently I create a NSDictionary and create a temp folder, I write dictionary as a plist to that temp folder and upload that .plist in that temp folder to dropbox.
Which is I guess not a good programming solution;
This works ok
if([title isEqualToString:#"Upload to Dropbox"])
{
//pass string in memory to nsdictionary
NSData * data = [_uploadPlistString dataUsingEncoding:NSUTF8StringEncoding];
NSString *errorDesc = nil;
NSPropertyListFormat format;
NSDictionary *uploadFile= (NSDictionary*)[NSPropertyListSerialization
propertyListFromData:data
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:&format
errorDescription:&errorDesc];
//create a temp folder
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:#"temp"];
NSLog(#"documents datapath: %#",dataPath);
//check if folder exist
NSError *error = nil;
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath])
[[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:&error]; //Create folder
//write dictionary to plist
NSString *pathTemp = [dataPath stringByAppendingPathComponent:#"agenda.plist"];
// write plist to disk
[uploadFile writeToFile:pathTemp atomically:YES];
//get last created file name from singleton
SingletonClass *sharedInstance=[SingletonClass sharedInstance];
NSString *destDirectory= sharedInstance.lastCreatedFolderName;
//set file name for dropbox
NSString *filename = #"agenda.plist";
[[self restClient] uploadFile:filename toPath:destDirectory
withParentRev:nil fromPath:pathTemp];
}
But How can I upload NSDictionary that is in memory, directly to Dropbox?
Without writing it to bundle or anything like that.

The Public API of the Dropbox SDK only support uploads directly from files.
However, since the SDK is open source you can easily extend it.
The main upload is happening in
- (void)uploadFile:(NSString*)filename toPath:(NSString*)path fromPath:(NSString *)sourcePath
params:(NSDictionary *)params
in DBRestClient.m.
You could add a category to DBRestClient and add a similar method for the upload that takes an NSData instead of a file path.
You can copy most of thier implementation, but instead of a filename you take an NSData. Change how the filename generation on dropbox works and instantiate the NSInputStream with a NSData instead of a file.
To get an NSData from your dictionary you can use an NSKeyedArchiver.

Related

Empty documents directory after creating file with NSFileHandle

I'm writing an application for the Apple watch. I'm using the following method (from this SE answer) to write to a log file:
- (void) writeLogWith: (NSString *) content {
//Get the file path
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *fileName = [documentsDirectory stringByAppendingPathComponent:#"whathappened.md"];
//create file if it doesn't exist
if(![[NSFileManager defaultManager] fileExistsAtPath:fileName])
[[NSFileManager defaultManager] createFileAtPath:fileName contents:nil attributes:nil];
//append text to file (you'll probably want to add a newline every write)
NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:fileName];
[file seekToEndOfFile];
[file writeData:[content dataUsingEncoding:NSUTF8StringEncoding]];
[file closeFile];
return;
}
I'm running it by plugging in my phone and running it directly on my watch. The function is definitely executing (I've stepped thought with the debugger) and it also knows that the file exists and doesn't repeatedly try and create it.
Xcode tells me that the file information is:
Printing description of documentsDirectory:
/var/mobile/Containers/Data/PluginKitPlugin/8503AD6C-6EC9-4522-A867-27109B01B615/Documents
Printing description of documentsDirectory:
(NSString *) documentsDirectory = 0x16d66890
Printing description of fileName:
(NSString *) fileName = 0x16d66950
Printing description of fileName:
/var/mobile/Containers/Data/PluginKitPlugin/8503AD6C-6EC9-4522-A867-27109B01B615/Documents/whathappened.md
I'd like to know if it's writing things correctly, but when I look at the container (following these SE answers), the documents directory is empty.
My question is: where did my file go? And how can I find it?
I think what might be giving you problems is the NSFileHandle object. I have written thousands upon thousands of files to the documents folder and I have never used NSFileHandle to do this. Simply use the built in method on NSString to write your string to the file path.
Try this:
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [[documentsDirectory stringByAppendingPathComponent:#"whathappened"] stringByAppendingPathExtension:#"md"];
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
}
NSString *string = #"The String You Want To Write.";
NSError *error;
[string writeToFile:filePath atomically:false encoding:NSUTF8StringEncoding error:&error];
if (error) {
NSLog(#"There was an error writing file\n%#", error.localizedDescription);
}
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSLog(#"File exists :)");
}
else {
NSLog(#"File does not exist :(");
}
From other research, the answer appears to be:
If you are storing a file on the Apple Watch, it is stored in it's own container, which isn't visible via xcode.
It indeed, appears to be related to this bug report: https://openradar.appspot.com/radar?id=5021353337946112, found via this SE: How to export shared container of an iOS App with Xcode6.2?

File Sync issue with Dropbox sync api on ios

I created a file on ios and add it to dropbox sync api to sync with the dropbox account.
Later when I edit the file, the file I edited did not show on dropbox. Here is what I did.
I created a file using ios FileManager like this:
if(![ABUtil fileExist:FILENAME]) {
NSString *st = #"This is a Test";
NSData *file = [st dataUsingEncoding:NSUTF8StringEncoding];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *file = [[paths objectAtIndex:0] stringByAppendingPathComponent:FILENAME];
[[NSFileManager defaultManager] createFileAtPath:
contents:file
attributes:nil];
}
Then I create a dropbox file for it like this:
DBAccount *account = [[DBAccountManager sharedManager] linkedAccount];
if (account) {
DBFilesystem *filesystem = [[DBFilesystem alloc] initWithAccount:account];
[DBFilesystem setSharedFilesystem:filesystem];
if([ABUtil fileExist:FILENAME]) {
DBPath *path = [[DBPath root] childPath:FILENAME];
DBFile *file = [filesystem createFile:path error:nil];
[file addObserver:self block:^(){
NSLog(#"FILE CHANGED");
}];
}
}
Later when I modify the file using on ios like this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *file = [[paths objectAtIndex:0] stringByAppendingPathComponent:FILENAME];
NSString *string = #"Tis is a test";
[string writeToFile:file atomically:YES encoding:NSUTF8StringEncoding error:nil];
The file did not change at dropbox directory!! Please help me how to make the file change sync with the dropbox!!!
EDIT I was mistaken. There is a method on NSString to write its contents to a file. So that part is presumably working. The next step would be to copy that file into Dropbox.
When you finish modifying the local file, you'll want to call writeContentsOfFile to upload that file to Dropbox.
Or you could skip the local file altogether, which is the more common pattern with the Dropbox Sync API. (Take a look at the Notes example that ships with the Sync SDK to see how to edit Dropbox files directly.)

Zip library issue

So I am using this library: https://github.com/flyingdolphinstudio/Objective-Zip
I implemented it and am trying to take a UIImage and NSString and make it a .png and .txt in the .zip file, respectively.
Now these are my 2 concerns, I am trying to save the *zipFile below to the documents directory.
Now with the dropbox API, how come I can't just provide the file itself and skip the path. It seems like I HAVE to save the .zip to the documents directory first and then get the path so I can then upload it to dropbox. Do I have to do that?
In the ...writeToFile line, I am getting a warning that ZipFile may not respond to writeToFile so how would I properly save it to the documents directory?
Anyway this is the code I have so far:
NSString *filename = [NSString stringWithFormat:#"%#.zip", textField.text];
ZipFile *zipFile= [[ZipFile alloc] initWithFileName:filename mode:ZipFileModeCreate];
//Image
NSString *nameImage = #"Image.png";
NSMutableDictionary *theDictionary = [Singleton sharedSingleton].dictionary;
NSData *data = [theDictionary objectForKey:#"image"];
ZipWriteStream *writeImage = [zipFile writeFileInZipWithName:nameImage compressionLevel:ZipCompressionLevelBest];
[writeImage writeData:data];
[writeImage finishedWriting];
//Text
NSString *nameText = #"Text.txt";
NSData *dataText = [textView.text dataUsingEncoding:NSUTF8StringEncoding];
ZipWriteStream *writeText = [zipFile writeFileInZipWithName:nameText compressionLevel:ZipCompressionLevelBest];
[writeText writeData:dataText];
[writeText finishedWriting];
//Now we HAVE to save it to the documents directory to get it to work with dropbox
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
NSString *filePath = [documentsPath stringByAppendingPathComponent:filename]; //Add the file name
[zipFile writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:NULL];
//Save to Dropbox
NSString *zipPath = [[NSBundle mainBundle] pathForResource:textField.text ofType:#"zip"];
[[self restClient] uploadFile:filename toPath:#"/" withParentRev:nil fromPath:zipPath];
So what am I doing wrong here?
Thanks!
It looks to me like ZipFile already writes to a file, so there's no need for something like writeToFile. Just initialize zipFile with the path you want, be sure to close the file at the end ([zipFile close]), and then upload to Dropbox as you would any other file.

Objective-Zip file folder structure ios

I have my App create a file, compress it into a .zip file, then attach it to an email. But the .zip file contains many directories before the actual file. Starting with the '/' which is a nameless folder and looks invisible to the people receiving it. The top level directory is '/', the next level is 'com'...
/var/mobile/Applications/CDA16BB231BDABABBA/Documents/data.txt
How can I remove all the directories and have the .zip file contain only the file?
Here's the code I have used...
NSError *error;
NSString *documentsDirectory = [NSHomeDirectory()
stringByAppendingPathComponent:#"Documents"];
NSString *filePath = [documentsDirectory
stringByAppendingPathComponent:#"data.txt"];
NSLog(#"string to write:%#",printString);
[printString writeToFile:filePath atomically:YES
encoding:NSUTF8StringEncoding error:&error];
////ZIP FILE/////
NSString *zipfilePath = [documentsDirectory stringByAppendingPathComponent:#"data.zip"];
[[NSFileManager defaultManager] removeItemAtPath: zipfilePath error: &error];
ZipFile *zipFile = [[ZipFile alloc]initWithFileName:zipfilePath mode:ZipFileModeCreate];
NSDictionary *attributes = [[NSFileManager defaultManager]attributesOfItemAtPath:zipfilePath error:&error];
NSDate *Date = [attributes objectForKey:NSFileCreationDate];
ZipWriteStream *stream = [zipFile writeFileInZipWithName:filePath fileDate:Date compressionLevel:ZipCompressionLevelBest];
NSData *data = [NSData dataWithContentsOfFile:filePath];
[stream writeData:data];
[stream finishedWriting];
[zipFile close];
The problem is that you are saying:
writeFileInZipWithName:filePath
The variable filePath contains that huge long name you are complaining about. It is the whole path from the top all the way down to your actual file.
Your file's name is #"data.txt", so what you want to say is:
writeFileInZipWithName:#"data.txt"

How can I save a JSON response to a file that would be accessible from within a local HTML file loaded inside UIWebWiew

I am receiving a JSON response and am currenlty able to make use of the data within my app.
I would like to save this response to a file so I could reference within an JS file located inside my project. I have already requested this data once when the application is launched so why not save it to a file and reference that throughout so only one call is needed for the data.
The HTML files for my UIWebView are imported into my Xcode project using the "create folder reference" option and the path to my JS file is html->js->app.js
I want to save the response as data.json somewhere on the device and then reference inside my js file like this request.open('GET', 'file-path-to-saved-json.data-file', false);
How can I achieve this?
After working with the idea some more here is what I came up with.
When the application is installed there is a default data file in the package that I copy to the Documents folder. When the application didFinishLaunchingWithOptions runs I call the following method:
- (void)writeJsonToFile
{
//applications Documents dirctory path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//live json data url
NSString *stringURL = #"http://path-to-live-file.json";
NSURL *url = [NSURL URLWithString:stringURL];
NSData *urlData = [NSData dataWithContentsOfURL:url];
//attempt to download live data
if (urlData)
{
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"data.json"];
[urlData writeToFile:filePath atomically:YES];
}
//copy data from initial package into the applications Documents folder
else
{
//file to write to
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"data.json"];
//file to copy from
NSString *json = [ [NSBundle mainBundle] pathForResource:#"data" ofType:#"json" inDirectory:#"html/data" ];
NSData *jsonData = [NSData dataWithContentsOfFile:json options:kNilOptions error:nil];
//write file to device
[jsonData writeToFile:filePath atomically:YES];
}
}
Then throughout the application when I need to reference the data, I use the saved file.
//application Documents dirctory path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSError *jsonError = nil;
NSString *jsonFilePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"data.json"];
NSData *jsonData = [NSData dataWithContentsOfFile:jsonFilePath options:kNilOptions error:&jsonError ];
To reference the json file in my JS code, I added a URL parameter for "src" and passed the file path to the Applications Documents folder.
request.open('GET', src, false);

Resources