iCloud Documents not visible - ios

I am trying to use iCloud Documents to store XML files from my iOS App. Everything seems to be working fine (I can write and read files without errors) except my App's files do not show up in iCloud Documents neither in icloud.com nor in developer.icloud.com nor on my Windows PC in iCloud Drive folder. I was running the app in simulator and tested with TestFlight on a real device. I have the latest version of iCloud for Windows 4.0 installed. The App is created in Xcode 6.
Does anyone know how to make the files appear in iCloud Documents?
The code I am using for the saving the file:
NSLog(#"Syncing with iCloud");
NSURL *ubiq = [filemgr URLForUbiquityContainerIdentifier:nil];
if (ubiq) {
NSURL *ubiquitousPackage = [ubiq URLByAppendingPathComponent:#"Documents" isDirectory:YES];
if ([filemgr fileExistsAtPath:[ubiquitousPackage path]] == NO)
[filemgr createDirectoryAtURL:ubiquitousPackage
withIntermediateDirectories:YES
attributes:nil
error:nil];
ubiquitousPackage = [ubiquitousPackage URLByAppendingPathComponent:#"data.pxa"];
DataFile *file = [[DataFile alloc] initWithFileURL:ubiquitousPackage];
file.xmlContent = doc.XMLString;
[file saveToURL:[file fileURL] forSaveOperation:UIDocumentSaveForCreating | UIDocumentSaveForOverwriting completionHandler:^(BOOL success) {
if (success) {
NSLog(#"Synced with iCloud: %#", [ubiquitousPackage path]);
} else {
NSLog(#"Syncing with iCloud failed");
}
}];
} else {
NSLog(#"iCloud not available");
}

I found out what the problem was:
The key in Info.plist for the iCloud container was a bit different from the format "iCloud.com.example.MyApp".

I follow instructions at this link to see files created by my app in iCloudDrive. I can see file from settings>iCloud>Storage from device. Hope it helps.

Related

iOS Files in Application Support Directory or Documents Directory deleted after update

I have an iOS app where i copy a mp3 file from the bundle to a directory within Application Support Folder (Btw same thing happens if i use the Documents folder), and later user's download more mp3 files they are also stored there. Everything works fine until an update is published (or i install another instance using Xcode during dev), where the app says the files do not exist at the path. I have tried everything and i am stumped why do my files always get deleted after an update or overwrite install using Xcode.
Here is my code:
//folder being created here
NSString *libraryPath = [[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:#"Tracks"];
[[NSFileManager defaultManager] createDirectoryAtPath:libraryPath
withIntermediateDirectories:YES
attributes:nil
error:&error];
if (error != nil) {
NSLog(#"error creating directory: %#", error);
}
//file about to be copied
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:#"Evening-Visualization-vph" ofType:#"mp3"];
libraryPath = [libraryPath stringByAppendingPathComponent:#"Evening-Visualization-vph.mp3"];
if(![[NSFileManager defaultManager] copyItemAtPath:sourcePath
toPath:libraryPath
error:&error]){
NSLog(#"Error Copying File from Bundle to Library");
}
NSURL * fileURL;
fileURL = [NSURL fileURLWithPath:libraryPath];
//file being marked so its not backed up to iCloud
if (![fileURL setResourceValue:[NSNumber numberWithBool: YES] forKey:NSURLIsExcludedFromBackupKey error:nil]) {
NSLog(#"Do not backup marked FAILED");
}
track.trackLocalPath = libraryPath;
The only solution i have left now is to manually check on each launch whether files exist at those path and mark my file list DB accordingly.

Save iOS 8 Documents to iCloud Drive

I want to have my app save the documents it creates to iCloud Drive, but I am having a hard time following along with what Apple has written. Here is what I have so far, but I'm not for sure where to go from here.
UPDATE2
I have the following in my code to manually save a document to iCloud Drive:
- (void)initializeiCloudAccessWithCompletion:(void (^)(BOOL available)) completion {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
self.ubiquityURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
if (self.ubiquityURL != nil) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"iCloud available at: %#", self.ubiquityURL);
completion(TRUE);
});
}
else {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"iCloud not available");
completion(FALSE);
});
}
});
}
if (buttonIndex == 4) {
[self initializeiCloudAccessWithCompletion:^(BOOL available) {
_iCloudAvailable = available;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfPath = [documentsDirectory stringByAppendingPathComponent:selectedCountry];
NSURL* url = [NSURL fileURLWithPath: pdfPath];
[self.manager setUbiquitous:YES itemAtURL:url destinationURL:self.ubiquityURL error:nil];
}];
}
I have the entitlements set up for the App ID and in Xcode itself. I click the button to save to iCloud Drive, and no errors pop up, the app doesn't crash, but nothing shows up on my Mac in iCloud Drive. The app is running on my iPhone 6 Plus via Test Flight while using iOS 8.1.1.
If I run it on Simulator (I know that it won't work due to iCloud Drive not working with simulator), I get the crash error: 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[3]'
Well, you've got me interested in this matter myself and as a result I've spent way to much time on this question, but now that I've got it working I hope it helps you as well!
To see what actually happens in the background, you can have a look at ~/Library/Mobile Documents/, as this is the folder where the files eventually will show up. Another very cool utility is brctl, to monitor what happens on your mac after storing a file in the iCloud. Run brctl log --wait --shorten from a Terminal window to start the log.
First thing to do, after enabling the iCloud ability (with iCloud documents selected), is provide information for iCloud Drive Support (Enabling iCloud Drive Support). I also had to bump my bundle version before running the app again; took me some time to figure this out. Add the following to your info.plist:
<key>NSUbiquitousContainers</key>
<dict>
<key>iCloud.YOUR_BUNDLE_IDENTIFIER</key>
<dict>
<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>
<key>NSUbiquitousContainerSupportedFolderLevels</key>
<string>Any</string>
<key>NSUbiquitousContainerName</key>
<string>iCloudDriveDemo</string>
</dict>
</dict>
Next up, the code:
- (IBAction)btnStoreTapped:(id)sender {
// Let's get the root directory for storing the file on iCloud Drive
[self rootDirectoryForICloud:^(NSURL *ubiquityURL) {
NSLog(#"1. ubiquityURL = %#", ubiquityURL);
if (ubiquityURL) {
// We also need the 'local' URL to the file we want to store
NSURL *localURL = [self localPathForResource:#"demo" ofType:#"pdf"];
NSLog(#"2. localURL = %#", localURL);
// Now, append the local filename to the ubiquityURL
ubiquityURL = [ubiquityURL URLByAppendingPathComponent:localURL.lastPathComponent];
NSLog(#"3. ubiquityURL = %#", ubiquityURL);
// And finish up the 'store' action
NSError *error;
if (![[NSFileManager defaultManager] setUbiquitous:YES itemAtURL:localURL destinationURL:ubiquityURL error:&error]) {
NSLog(#"Error occurred: %#", error);
}
}
else {
NSLog(#"Could not retrieve a ubiquityURL");
}
}];
}
- (void)rootDirectoryForICloud:(void (^)(NSURL *))completionHandler {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *rootDirectory = [[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]URLByAppendingPathComponent:#"Documents"];
if (rootDirectory) {
if (![[NSFileManager defaultManager] fileExistsAtPath:rootDirectory.path isDirectory:nil]) {
NSLog(#"Create directory");
[[NSFileManager defaultManager] createDirectoryAtURL:rootDirectory withIntermediateDirectories:YES attributes:nil error:nil];
}
}
dispatch_async(dispatch_get_main_queue(), ^{
completionHandler(rootDirectory);
});
});
}
- (NSURL *)localPathForResource:(NSString *)resource ofType:(NSString *)type {
NSString *documentsDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *resourcePath = [[documentsDirectory stringByAppendingPathComponent:resource] stringByAppendingPathExtension:type];
return [NSURL fileURLWithPath:resourcePath];
}
I have a file called demo.pdf stored in the Documents folder, which I'll be 'uploading'.
I'll highlight some parts:
URLForUbiquityContainerIdentifier: provides the root directory for storing files, if you want to them to show up in de iCloud Drive on your Mac, then you need to store them in the Documents folder, so here we add that folder to the root:
NSURL *rootDirectory = [[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]URLByAppendingPathComponent:#"Documents"];
You also need to add the file name to the URL, here I copy the filename from the localURL (which is demo.pdf):
// Now, append the local filename to the ubiquityURL
ubiquityURL = [ubiquityURL URLByAppendingPathComponent:localURL.lastPathComponent];
And that's basically it...
As a bonus, check out how you can provide an NSError pointer to get potential error information:
// And finish up the 'store' action
NSError *error;
if (![[NSFileManager defaultManager] setUbiquitous:YES itemAtURL:localURL destinationURL:ubiquityURL error:&error]) {
NSLog(#"Error occurred: %#", error);
}
If you are intending to work with UIDocument and iCloud, this guide from Apple is pretty good:
https://developer.apple.com/library/ios/documentation/DataManagement/Conceptual/UsingCoreDataWithiCloudPG/Introduction/Introduction.html
EDITED:
Don't know of any better guide of hand, so this may help:
You will need to fetch the ubiquityURL using the URLForUbuiquityContainerIdentifier function on NSFileManager (which should be done asynchronously).
Once that is done, you can use code like the following to create your document.
NSString* fileName = #"sampledoc";
NSURL* fileURL = [[self.ubiquityURL URLByAppendingPathComponent:#"Documents" isDirectory:YES] URLByAppendingPathComponent:fileName isDirectory:NO];
UIManagedDocument* document = [[UIManagedDocument alloc] initWithFileURL:fileURL];
document.persistentStoreOptions = #{
NSMigratePersistentStoresAutomaticallyOption : #(YES),
NSInferMappingModelAutomaticallyOption: #(YES),
NSPersistentStoreUbiquitousContentNameKey: fileName,
NSPersistentStoreUbiquitousContentURLKey: [self.ubiquityURL URLByAppendingPathComponent:#"TransactionLogs" isDirectory:YES]
};
[document saveToURL:fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
}];
You'll also want to look into using NSMetadataQuery to detect documents uploaded from other devices and potentially queue them for download, and observing the NSPersistentStoreDidImportUbiquitousContentChangesNotification to find about changes made via iCloud, among other things.
** Edit 2 **
Looks like you are trying to save a PDF file, which is not quite what Apple considers a "document" in terms of iCloud syncing. No need to use UIManagedDocument. Remove the last 3 lines of your completion handler and instead just use NSFileManager's
setUbiquitous:itemAtURL:destinationURL:error: function. The first URL should be a local path to the PDF. The second URL should be the path within the ubiquiuty container to save as.
You may also need to look into NSFileCoordinator perhaps.
I think this guide from Apple may be the most relevant:
https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/iCloud/iCloud.html

How to hide folder in NSDocumentsDirectory and disallow backup via iTunes & iCloud

I create private folder in NSDocumentDirectory and i want to hide it in iTunes and disallow to backup.
In this question How to hide folders created in Document Directory in ios? people suggest to save in private directory.
But it's not ok according apple documentation https://developer.apple.com/library/mac/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html
Application_Home/Library/ You should not use this directory for user data files.
Before iTunes11 this solution was work for me
Can I add the Do not Back up for the "Document Directory" for iCloud
but now i see folder with private docs in iTunes.
Could somebody help me?
For hiding your app from iTunes file sharing, you can set the below key to No in your info.plist.
Application supports iTunes file sharing
Alternatively, prepend your filenames / directories added the the Documents directory with a . to hide it without disabling iTunes File Sharing. E.g. .folderName.
Use this to prevent iCloud backup, from Prevent Backup to iCloud,is following code correct?
- (BOOL)addSkipBackupAttributeToItemAtPath:(NSString *)filePathString {
NSURL *fileURL = [NSURL fileURLWithPath:filePathString];
assert([[NSFileManager defaultManager] fileExistsAtPath: [fileURL path]]);
NSError *error = nil;
BOOL success = [fileURL setResourceValue:[NSNumber numberWithBool: YES]
forKey: NSURLIsExcludedFromBackupKey
error: &error];
return success;
}
And to prevent app backup from XCode Organizer when the device is locked, use this snippet
//************************************************************************
// Method for making files and folders secure
//************************************************************************
+ (void)makeItemAtPathSecure:(NSString *)path
{
NSError *securingFilesError;
NSFileManager *manager=[NSFileManager defaultManager];
NSDictionary *attrs = [manager attributesOfItemAtPath:path error:&securingFilesError];
if(![[attrs objectForKey:NSFileProtectionKey] isEqual:NSFileProtectionComplete])
{
if(![manager setAttributes:[NSDictionary dictionaryWithObject:NSFileProtectionComplete forKey:NSFileProtectionKey] ofItemAtPath:path error:&securingFilesError])
{
NSLog(#"Problem in securing files: %#",[securingFilesError localizedDescription]);
}
}
else
{
NSLog(#"Problem in securing files: %#",[securingFilesError localizedDescription]);
}
}
For selectively hiding folders in iTunes try renaming the folder with a . before it, like folderName should be .folderName

How to Delete an iCloud ubiquity containers on the iPhone?

I have the same issue as this question where the iCloud ubiquity container is not being cleaned up when I delete the app.
But when I try to delete the ubiquity container I get an error message (The operation couldn’t be completed. (Cocoa error 513.)). How can I delete it?
This is what I'm using:
NSString *path = #"/private/var/mobile/Library/Mobile Documents/XXXXXX";
[[NSFileManager defaultManager] removeItemAtPath:path error:&error];
EDIT: Even if I delete the App on the device and all iCloud data (Settings App->iCloud->Storage & Backup->Manage Storage->App Name) there's still some data left over on the iCloud ubiquity container. This is the data I want to delete the first time the app is launched (in case the user re-installs the app).
You should be able to remove files INSIDE the ubiquity container by going to Settings App->iCloud->Storage & Backup->Manage Storage->App Name and then delete any files. I think you may only see files in the iCloud/Documents directory though so you may need code to clear anything else.
Alternately use a Mac and go to ~/Library/Mobile Documents and remove files there.
To get the iCloud container use this:
NSURL *iCloudURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:ubiquityID];
where ubiquityID is your apps iCloud container ID.
To list all files in the iCloud container use something like this passing in the iCloudURL
/*! Recursively lists all files
#param dir The directory to list
#param padding A string padding to indent the output depending on the level of recursion
*/
- (void)listAllFilesInDirectory:(NSURL*)dir padding:(NSString*)padding {
NSArray *docs = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:dir includingPropertiesForKeys:nil options:0 error:nil];
for (NSURL* document in docs) {
FLOG(#" %# %#", padding, [document lastPathComponent]);
BOOL isDir;
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:document.path isDirectory:&isDir];
if (fileExists && isDir) {
[self listAllFilesInDirectory:document padding:[NSString stringWithFormat:#" %#", padding]];
}
}
}
And to delete stuff from the ubiquity container you need to user a fileCoordinator something like this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
NSFileCoordinator* fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fileCoordinator coordinateWritingItemAtURL:fileURL options:NSFileCoordinatorWritingForDeleting
error:nil byAccessor:^(NSURL* writingURL) {
NSFileManager* fileManager = [[NSFileManager alloc] init];
NSError *er;
//FLOG(#" deleting %#", writingURL);
bool res = [fileManager removeItemAtURL:writingURL error:&er];
if (res) {
LOG(#" iCloud files removed");
}
else {
LOG(#" document NOT removed");
FLOG(#" error %#, %#", er, er.userInfo);
}
}];
}

Referencing files within an iPad Application

I'm developing an iPad App & currently testing it on the device itself - I'm using an sqlite database to read in the urls of .m4v movie files.
For testing using the simulator I list urls in the database as follows:
/Users/Octave1/Desktop/iDev/Moodymann/IMM Simulator App/Content/Movies/visuals seg0.m4v
.
.
.
This works fine & the database is read correctly, & the files play as required.
When I run the App on the iPad I change the urls in the database to the following format:
/Content/Movies/visuals seg0.m4v
.
.
.
However the movie doesn't play at all. It seems like there is a problem with the path & that the files aren't being found - anyone know the correct way to reference files within the Application itself?
Thanks in advance :)
I figured this out, for anyone with the same issue.
First of all - I copied my "Content" folder over to the iPad, placing it in the Library Directory, as follows:
//Finding out where the Library Directory is located
NSString *libraryDirectory = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
//Find where my content folder is initially
NSString *contentPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Content"];
NSError *error = nil;
[[NSFileManager defaultManager] copyItemAtPath:contentPath
toPath:libraryDirectory
error:&error];
if([[NSFileManager defaultManager] copyItemAtPath:contentPath toPath:folderPath error:&error]){
NSLog(#"File successfully copied");
} else {
NSLog(#"Error description-%# \n", [error localizedDescription]);
NSLog(#"Error reason-%#", [error localizedFailureReason]);
}
I can then read out the address of each movie, & append each address to the address of the libarary
NSString *inFilePath = movieObj.pathToMovie; ///Content/Movies/visuals seg0.m4v from above
NSLog(#"inFilePath is: %#", inFilePath);
NSString *fullPath = [libraryDir stringByAppendingPathComponent:[[NSString alloc] initWithString:inFilePath]];
NSLog(#"fullPath is: %#", fullPath);
NSURL *url = [[NSURL alloc] initFileURLWithPath:fullPath];
NSLog(#"url is: %#", url);
[movieUrlArray addObject:url];
Now I know the urls of the movie files, within the Application's file system.

Resources