2.23 – Apps must follow the iOS Data Storage Guidelines or they will be rejected [FIXED]

If you have run into an iOS application rejection based on the 2.23 iOS guideline regarding an application exceeding fair use of the iCloud backup storage then you will need to make sure all files your application downloads or creates, that are not user specific and that do not need to be backed up, are removed from the iCloud backup set for the application. This can be done by applying the NSURLIsExcludedFromBackupKey key to all of those files using the following method.

You can add this method to your AppDelegate or some other singleton within your application and have access to it from anywhere within your project using the following code:

// Make sure file is removed from the iCloud image backup system
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate addSkipBackupAttributeToItemAtURL:imagePath];

// Removes all application assets that are not user created from the iCloud backup system
// by adding the NSURLIsExcludedFromBackupKey to every file that is downloaded and stored
// in the application's document directory
-(BOOL)addSkipBackupAttributeToItemAtURL:(NSString *)fileString {
    
    // Convert string path to NSURL
    NSURL * fileURL = [NSURL fileURLWithPath:fileString];
    
    // Make sure file has already been created before applying key
    if (![[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]]) {
        NSLog(@"File Missing: %@",[fileURL path]);
        return NO;
    }
    
    // Obtain iOS version for proper key application
    NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
    
    // 5.0.1 requires <sys/xattr.h>
    if ([currSysVer isEqualToString:@"5.0.1"]) {
        const char* filePath = [[fileURL path] fileSystemRepresentation];
        const char* attrName = "com.apple.MobileBackup";
        u_int8_t attrValue = 1;
        int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
        NSLog(@"Excluded '%@' from backup",fileURL);
        return result == 0;
    }
    // Above 5.0.1 use NSURLIsExcludedFromBackupKey key
    else if (&NSURLIsExcludedFromBackupKey) {
        NSError *error = nil;
        BOOL result = [fileURL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];
        if (result == NO) {
            NSLog(@"File '%@' could not be excluded from iCloud backup set. Error: %@",fileURL, error);
            return NO;
        }
        else {
            NSLog(@"File '%@' has been removed from iCloud backup set.",fileURL);
            return YES;
        }
    } else {
        // iOS version is below 5.0, no need to do anything
        return YES;
    }
}

Published by

Tim Clark

Experienced Business Owner, Chief Information Officer, Vice President, Chief Software Architect, Application Architect, Project Manager, Software Developer, Senior Web Developer, Graphic Designer & 3D Modeler, University Instructor, University Program Chair, Academic Director. Specialties: Ruby, Ruby on Rails, JavaScript, JQuery, AJAX, Node.js, React.js, Angular.js, MySQL, PostgreSQL, MongoDB, SQL Server, Responsive Design, HTML5, XHTML, CSS3, C#, ASP.net, Project Management, System Design/Architecture, Web Design, Web Development, Adobe CS6 (Photoshop, Illustrator)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s