14

Apple just rejected a PhoneGap app I submitted. I utilize HTML5 localStorage in the app to save downloaded data for caching purposes: 2.23 Apps must follow the iOS Data Storage Guidelines or they will be rejected.

I'm seriously confused because if anything I thought localStorage in 5.1 actually saves data in cache and NOT in a place that gets backed up with iCloud [source]. This is the behavior I want - I don't need or want the data to be backed up.

Am I wrong or is Apple? What can I do in a PhoneGap app to save this cached data without being in violation?

Edit: PhoneGap 1.8.1 if that helps.

Community
  • 1
  • 1
Rob Lauer
  • 3,075
  • 1
  • 32
  • 44
  • 2
    I would suggest you use Xcode to download a snapshot of your app's sandbox to take a look at what files and directories are being created. Perhaps PhoneGap is doing something funky. You could also just look in the app's Simulator directory too. – Mike Weller Sep 05 '12 at 13:26
  • And make sure to show hidden files because many of the cache/implementation detail directories are hidden (ex: Core Data external resource storage). – Jack Lawrence Sep 05 '12 at 14:34
  • If I look in the simulator directory, it shows a file__0.localstorage in the "Caches" directory (Applications/app/Library/Caches). So that re-affirms my thought that it is saved in the "correct" place. – Rob Lauer Sep 05 '12 at 18:21

3 Answers3

11

It turns out I was right and Apple was wrong. I confirmed that I was storing everything in the /Caches directory properly. They didn't comment on my question - just approved my app.

Rob Lauer
  • 3,075
  • 1
  • 32
  • 44
  • 1
    If you are only using localStorage you should point that out to the reviewer (and/or send them to this thread!) – Rob Lauer Sep 19 '13 at 08:57
2

There are two things that I am aware of:

1) Files that are generated by your app (and not a result of the user using your app) such as temporary text files to store a variable's value, then these files must be placed in the Library/Cache instead of the Document directory.

2) You must also mark a file with a "skip-backup" attribute to tell iCloud not to backup the file.

I think you might be missing step 2.

I wrote a simple MediaDirectory class which quickly gives me the path to the files in the Library/Cache folder and also add the skip backup attribute.

After you saved your file to the Libary/Cache folder, you simply go something like this:

[MediaDirectory addSkipBackupAttributeForFile:@"myTextFile.txt"];

Here's the class in full:

// Header File

// ----------------------------------------------------------------------
// This class takes a file name (including extension) and returns
// the path to that file in the Library/Cache folder
// ----------------------------------------------------------------------

#import <Foundation/Foundation.h>

@interface MediaDirectory : NSObject

+(NSString *) mediaPathForFileName:(NSString *) fileName;
+(NSString *) mediaPathForFileName:(NSString *) fileName inSubDirectory:(NSString *) subDirectory;
+ (BOOL)addSkipBackupAttributeToFile:(NSString *) fileName;
+ (BOOL)addSkipBackupAttributeToFile:(NSString *) fileName inSubDirectory:(NSString *) subDirectory;

@end


// Implementation File

#import "MediaDirectory.h"
#include <sys/xattr.h>

@implementation MediaDirectory

+(NSString *) mediaPathForFileName:(NSString *) fileName
{   
    NSArray *directoryPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *cachesDirectory = [directoryPaths objectAtIndex:0];
    NSString *filePath = [NSString stringWithFormat:@"%@/%@", cachesDirectory, fileName];

    return filePath;
}

// if an image needs to be stored in a sub folder called "images"
+(NSString *) mediaPathForFileName:(NSString *) fileName inSubDirectory:(NSString *) subDirectory
{   
    NSArray *directoryPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *cachesDirectory = [directoryPaths objectAtIndex:0];
    NSString *filePath = [NSString stringWithFormat:@"%@/%@/%@", cachesDirectory, subDirectory, fileName];

    return filePath;
}

//+ (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
+ (BOOL)addSkipBackupAttributeToFile:(NSString *) fileName
{
    const char* filePath = [[self mediaPathForFileName:fileName] 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;
}

+ (BOOL)addSkipBackupAttributeToFile:(NSString *) fileName inSubDirectory:(NSString *) subDirectory
{
    const char* filePath = [[self mediaPathForFileName:fileName inSubDirectory:subDirectory] 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;
}

@end
Zhang
  • 11,549
  • 7
  • 57
  • 87
1

A phonegap app I just submitted has been rejected by apple for the same reasons, and I'm only using localstorage.

I have resubmitted with the following preference set in my config.xml

<preference name="BackupWebStorage" value="none" />

I understand this will resolve the issue

ED-209
  • 4,706
  • 2
  • 21
  • 26