我有一个带有预先填充的.sqlite文件的应用程序,该文件在首次打开应用程序时被复制到用户的Documents目录中。这个文件是12.9MB。现在两次,我的应用程序已被拒绝,因为使用此拒绝注释将目标更改为iOS5:
二进制被拒绝2012年4月24日上午10:12
拒绝理由:
2.23应用必须遵循iOS数据存储指南,否则将被拒绝
2012年4月24日上午10:12来自Apple。
2.23
我们发现您的应用不符合iOS数据存储指南,这是App Store审核指南所要求的。
特别是,我们发现在内容下载中,您的应用程序存储了12.81 MB。要检查应用存储的数据量:
- 安装并启动您的应用
- 转到设置> iCloud>存储&备份>管理存储
- 如有必要,请点按“显示所有应用”
- 检查应用的存储空间
iOS数据存储指南指出,只有用户使用您的应用创建的内容(例如文档,新文件,编辑等)可以存储在/ Documents目录中 - 并由iCloud备份。
您的应用使用的临时文件只应存储在/ tmp目录中;请记得在用户退出应用程序时删除存储在此位置的文件。
可以重新创建但必须保持应用程序正常运行的数据 - 或者因为客户希望它可供脱机使用 - 应标记为“不备份”属性。对于NSURL对象,请添加NSURLIsExcludedFromBackupKey属性以防止备份相应的文件。对于CFURLRef对象,请使用相应的kCFURLIsExcludedFromBackupKey属性。
有关详细信息,请参阅技术问答1719:如何阻止文件备份到iCloud和iTunes?
有必要修改您的应用以满足iOS数据存储指南的要求。
我已尝试按照“数据存储指南”中的建议设置“不备份”属性,但又被拒绝了。
我在我的应用中没有使用iCloud,而且设置> iCloud>等根本没有用。
我无法使用Caches
或tmp
目录,因为用户在创建后会修改数据库。
我似乎介于摇滚和硬地之间,Apple不允许这种应用程序运行。
有没有人遇到这个问题并设法克服它?
编辑17-5-12 我还没有设法让这个应用程序获得批准。有没有人设法做到这一点?
编辑1-7-12 出于同样的原因,我的应用程序再次遭到拒绝。我不知道该怎么做,当然这是一种常见的用途。
编辑11-9-12 应用程序现已批准 - 请参阅下面的解决方案。我希望它可以帮助别人。
答案 0 :(得分:9)
好的,这是我设法获得批准的解决方案(最后!)
这是设置“跳过备份”属性的代码 - 请注意,5.0.1及以下版本和5.1及以上版本不同。
#include <sys/xattr.h>
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
if (&NSURLIsExcludedFromBackupKey == nil) { // iOS <= 5.0.1
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;
} else { // iOS >= 5.1
NSError *error = nil;
[URL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];
return error == nil;
}
}
这是我的persistentStoreCoordinator
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (__persistentStoreCoordinator != nil)
{
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"store.sqlite"];
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *storePath = [[[self applicationDocumentsDirectory] path] stringByAppendingPathComponent:@"store.sqlite"];
// For iOS 5.0 - store in Caches and just put up with purging
// Users should be on at least 5.0.1 anyway
if ([[[UIDevice currentDevice] systemVersion] isEqualToString:@"5.0"]) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [paths objectAtIndex:0];
NSString *oldStorePath = [storePath copy];
storePath = [cacheDirectory stringByAppendingPathComponent:@"store.sqlite"];
storeURL = [NSURL URLWithString:storePath];
// Copy existing file
if ([fileManager fileExistsAtPath:oldStorePath]) {
[fileManager copyItemAtPath:oldStorePath toPath:storePath error:NULL];
[fileManager removeItemAtPath:oldStorePath error:NULL];
}
}
// END iOS 5.0
if (![fileManager fileExistsAtPath:storePath]) {
// File doesn't exist - copy it over
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"store" ofType:@"sqlite"];
if (defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
}
}
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
[self addSkipBackupAttributeToItemAtURL:storeURL];
return __persistentStoreCoordinator;
}
请注意,我决定只在Caches
存储,并忍受对iOS 5.0用户的清除。
本月苹果公司批准了这项计划。
请不要复制并粘贴此代码而不首先阅读和理解它 - 它可能不完全准确或优化,但我希望它可以引导某人找到帮助他们的解决方案。
答案 1 :(得分:4)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#include <sys/xattr.h>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Put this in your method
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSURL *pathURL= [NSURL fileURLWithPath:documentsDirectory];
iOS5 = NO;
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"5.0.1")) {
iOS5 = YES;
}
// Set do not backup attribute to whole folder
if (iOS5) {
BOOL success = [self addSkipBackupAttributeToItemAtURL:pathURL];
if (success)
NSLog(@"Marked %@", pathURL);
else
NSLog(@"Can't marked %@", pathURL);
}
}
- (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;
}
答案 2 :(得分:1)
你说你不使用iCloud。在这种情况下,您只需将sqlite
文件移动到后缀为.nosync
的目录即可。应该这样做!
NSString *dataFileName = @"my.sqlite";
NSString *dataFileDirectoryName = @"Data.nosync";
NSString *documentsDirectoryPath = [self applicationDocumentsDirectory];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:[documentsDirectoryPath stringByAppendingPathComponent:dataFileDirectoryName]] == NO) {
NSError *fileSystemError;
[fileManager createDirectoryAtPath:[documentsDirectoryPath stringByAppendingPathComponent:dataFileDirectoryName]
withIntermediateDirectories:YES
attributes:nil
error:&fileSystemError];
if (fileSystemError != nil) {
NSLog(@"Error creating database directory %@", fileSystemError);
}
}
NSString *dataFilePath = [[documentsDirectoryPath
stringByAppendingPathComponent:dataFileDirectoryName]
stringByAppendingPathComponent:dataFileName];
// Move your file at dataFilePath location!
HTH。
答案 3 :(得分:0)
我一直在研究这个问题并找到了关于这个主题的非常有趣的文章:http://iphoneincubator.com/blog/data-management/local-file-storage-in-ios-5
如果您尝试使用/ Documents文件夹存储数据库文件,我相信您将继续被拒绝。
我建议你咬紧牙关并使用/ Cache。最糟糕的用户案例场景是他们的设备内存不足,应用程序清理后删除了DB文件。在这种情况下,当您的应用程序再次启动时,它应该将捆绑的DB文件复制到/ Cache中,并且用户将同步以从远程服务器获取多余的数据。这假设这是你的应用程序的工作方式。
要让您的应用程序将数据库文件从/ Documents移动到/ Cache,您可以告诉NSFileManager为您执行此操作...
#define FILE_MANAGER [NSFileManager defaultManager]
#define DOCUMENTS_PATH [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex: 0]
#define CACHES_PATH [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex: 0]
#define DB_DOCS_PATH [DOCUMENTS_PATH stringByAppendingPathComponent: @"database.db"]
#define DB_PATH [CACHES_PATH stringByAppendingPathComponent: @"database.db"]
if([FILE_MANAGER moveItemAtPath: DB_DOCS_PATH toPath:DB_PATH error:&error])
{
NSLog(@"SUCCESSFULLY MOVED %@ to %@",DB_DOCS_PATH,DB_PATH);
}
这将阻止现有用户不必要地使用其iCloud存储空间。