简体   繁体   中英

Prevent iCloud sync of data (using .nosync?)

EDIT: So far, the best I've been able to come up with is a pop-up to ask the user to disable iCloud sync, along with moving all the data to the Documents directory so it won't get wiped: In iOS5, is it possible to detect if a user has an app set to back up?

I develop offline mapping application for iPhone/iPad.

We used to store all of the data (many gigs potentially) in the Caches directory.

As of iOS5, the files in the Caches directory can be randomly deleted when the user's hard drive starts getting full.

How can I store local data, without the data being synced to iCloud, iTunes, and without it being randomly deleted? My local data is a large directory tree with many small data files, in thousands of subdirectories.

I moved our directory tree from the library cache directory to a data.nosync directory in the documents directory, because we had read this might be a solution. However, the data in the nosync folder is still being backed up to iCloud.

Here is now I create the directory:

NSString* noSyncDirectory() {
  static NSString *directory = nil;
  if (!directory) {
    directory = [[NSString stringWithFormat:@"%@/%@",
                  documentsDirectory(), @"data.nosync"] retain];
    [Constants createDirectoryIfNeeded:directory];
  }
  return directory;
}

From: https://developer.apple.com/library/ios/#qa/qa1719/_index.html

You can use the following method to set the "do not back up" extended attribute. Whenever you create a file or folder that should not be backed up, write the data to the file and then call this method, passing in a URL to the file.

#include <sys/xattr.h>
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
    const char* filePath = [[URL path] fileSystemRepresentation];

    const char* attrName = "com.apple.MobileBackup";
    u_int8_t attrValue = 1;

    int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
    return result == 0;
}

More information can be found: https://developer.apple.com/icloud/documentation/data-storage/

Further note: While the developer documentation incorrectly implies ("These files will not be purged and will not be included in the user's iCloud or iTunes backup.") that the do-not-backup flag doubles as a do-not-purge flag that is not the case. Simply leaving files in the Caches Directory and flagging them do-not-backup will not prevent their wipe.

This issue might not have a workaround yet... You could possibly try calling URLForUbiquityContainerIdentifier explicitly, since it does some initialization on the first invocation. Then create a sub-directory with a .nosync suffix (based on this example ).

The first time you call this method for a given container directory, iOS extends your application sandbox to include that container directory. Thus, it is important that you call this method at least once before trying to search for files in iCloud. And if your application accesses multiple container directories, you should call the method once for each directory.

The doc on .nosync :

To ensure that the persistent store itself is not synced by iCloud: when you set a value for the NSPersistentStoreUbiquitousContentNameKey, UIManagedDocument puts the persistent store in a .nosync directory inside the document package. If you make use of additional content (using the writeAdditionalContent:toURL:originalContentsURL:error: method), you must make sure that the document directory is not a package. Typically you give the document directory an extension that is not recognized as a document extension.

You may want to ensure you have the com.apple.developer.ubiquity-container-identifiers entitlement.

The iCloud Containers field identifies the list of container directories that your app can access in the user's iCloud storage. (This field corresponds to the com.apple.developer.ubiquity-container-identifiers entitlement.)

Perhaps you can disable backup for your app and store data files somewhere else in the app tree. Any stuff that needs to be backed can be put in a common area outside your app.

You might be able to do it in provisioning: invalid code signing app submission

or settings :

When you want to give the user the option to enable or disable iCloud usage entirely for your app. If your app includes a Settings bundle or inline preferences, you could include a preference to toggle whether your app stores content in iCloud at all. For example, an app whose data consists entirely of privately managed files might do this to give the user the choice of how those files are stored.

or by removing the com.apple.developer.ubiquity-container-identifiers entitlement (which could get auto-added) with Xcode: Configuring Your App's iCloud Entitlements

Otherwise you might need to issue a warning with instructions on disabling through the UI:

http://www.pcmag.com/article2/0,2817,2394702,00.asp#fbid=bpIwPLZ1HeQ

Another workaround is to group the maps into collections that are installed as separate applications. That would be a way to store the data without creating any directories that sync or get backed-up. The data will be stored in the the .app directory and will be protected.

Depending on how the cache space reclamation function works, it might not delete recently accessed or modified files. You could try periodically touching them on a timer. You could also add some old files as decoys and detect when they've been deleted or when space is low to at least issue a warning or re-download the deleted objects...

There is a newer way to prevent iCloud syncing of data without using extended attributes directly:

- (BOOL)addSkipBackupAttributeToItemAtPath:(NSString *) filePathString
{
    NSURL* URL= [NSURL fileURLWithPath: filePathString];
    assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);

    NSError *error = nil;
    BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
                                  forKey: NSURLIsExcludedFromBackupKey error: &error];
    if(!success){
        NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error);
    }
    return success;
}

See Apple's Technical Q&A QA1719 for more details.

Maybe uncheck "Enable Entitlements" in the summary pane of the project or edit the profile to remove the *ubiquity settings. ( Notes for ios 5 beta 7 reference entitlements.)

There is also the setUbiquitous function:

setUbiquitous:itemAtURL:destinationURL:error:

Sets whether the item at the specified URL should be stored in the cloud.

Parameters

flag

Specify YES to move the item to iCloud or NO to remove it from iCloud (if it is there currently).

http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSFileManager_Class/Reference/Reference.html#//apple_ref/occ/instm/NSFileManager/setUbiquitous:itemAtURL:destinationURL:error :

Did you try just naming the directory ".nosync" without the data in front? It could be generally . directories are ignored, or perhaps that specifically.

But, it seems like the behavior is just as a user would want it - potentially gigs of space used by an application they may not be using currently, where the space could be reclaimed automatically. I am not sure but you would think the system would be smart about reclaiming files created recently only after there was no choice, so if the user had just stored maps recently they would not be deleted unless there was no other choice.

For the purposes of filing a bug I am going to ask for a way to mark a directory for user prompting before deletion - so that if they are syncing a lot of movies and it would clear out a data set like the maps you are talking about, the user would be asked if they want to remove the data "offline maps" from application "MyCoolMapper" to proceed with the sync.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM