2014-06-11 43 views
0

我有一個AppStore上的應用程序,它在12月13日提交使用Xcode 4.3,它有一個核心數據模型(版本2)。我現在要發佈已更新核心數據模型的下一個版本。當我在調試模式下運行代碼時,遷移工作正常。但是當我通過TestFlight進行發佈時,遷移失敗並且出現以下錯誤。出於安全原因,每次應用程序退出時(我保存加密副本),我都會刪除數據庫,並在下次啓動時解密此數據庫。iOS7.1上現有應用的核心數據更新失敗

用於初始化PersistentStoreCoordinator的代碼。

NSError *error = nil; 
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; 
NSDictionary *options = @{ 
          NSMigratePersistentStoresAutomaticallyOption : @YES, 
          NSInferMappingModelAutomaticallyOption : @YES 
          }; 


// Check if we need a migration 
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:storeURL error:&error]; 
NSManagedObjectModel *destinationModel = [_persistentStoreCoordinator managedObjectModel]; 
BOOL isModelCompatible = (sourceMetadata == nil) || [destinationModel isConfiguration:nil compatibleWithStoreMetadata:sourceMetadata]; 
if (! isModelCompatible) { 
    // We need a migration, so we set the journal_mode to DELETE 
    options = @{NSMigratePersistentStoresAutomaticallyOption:@YES, 
       NSInferMappingModelAutomaticallyOption:@YES, 
       NSSQLitePragmasOption: @{@"journal_mode": @"DELETE"} 
       }; 
} 

NSPersistentStore *persistentStore = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]; 
if (! persistentStore) { 


    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documents = [paths objectAtIndex:0]; 
    NSString *databasePath = [documents stringByAppendingPathComponent:@"Store"]; 
    NSString *sqlite = [databasePath stringByAppendingPathComponent:@"myDatabase.sqlite"]; 

    [[NSFileManager defaultManager] removeItemAtPath:sqlite error:nil]; 

    NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    //abort(); 
} 

// Reinstate the WAL journal_mode 
if (! isModelCompatible) { 
    [_persistentStoreCoordinator removePersistentStore:persistentStore error:NULL]; 
    options = @{NSMigratePersistentStoresAutomaticallyOption:@YES, 
       NSInferMappingModelAutomaticallyOption:@YES, 
       NSSQLitePragmasOption: @{@"journal_mode": @"WAL"} 
       }; 
    [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]; 
} 

return _persistentStoreCoordinator; 

當我嘗試初始化persistentStoreCoordinator時,出現以下錯誤。

未解決的錯誤錯誤域= NSCocoaErrorDomain代碼= 259的UserInfo = 0x15df4dc0 {NSUnderlyingException =文件在路徑不出現是一個SQLite數據庫「該操作不能完成(可可誤差259)。」:/無功/移動/應用/ 9B623099-5591-4C55-BA83-77A057B94690 /文檔/存儲/ myDatabase.sqlite},{

NSUnderlyingException = "File at path does not appear to be a SQLite database: /var/mobile/Applications/9B623099-5591-4C55-BA83-77A057B94690/Documents/Store/myDatabase.sqlite";} 

奇怪的是,在iOS7.0.6的升級方案工作得很好無論是在開發和發佈配置,但在iOS7.1上,它似乎只適用於開發配置。我厭倦了刪除WAL和SHM文件,但無濟於事。

回答

1

錯誤信息非常明顯。它說:

NSUnderlyingException = "File at path does not appear to be a SQLite database: /var/mobile/Applications/9B623099-5591-4C55-BA83-77A057B94690/Documents/Store/myDatabase.sqlite";}

我在想,這可能是由於更新後的核心數據的SQLite與WAL文件之間的不匹配,但後來事實證明過程中的錯誤是更多的是用鑰匙不匹配加密 - 解密過程。這是我的第一次猜測,我已經讓我的同事檢查了這一點,但他以某種方式驗證了這一點,並且我們拒絕了這個理論。

我們的加密通過將部分運行時間生成的加密密鑰保存到鑰匙串中。現在前提是應用升級之前和升級之後的鑰匙串中的價值仍然存在。但是由於使用了錯誤的Bundle標識符,升級後的應用程序沒有從鑰匙串獲取值,並創建了自己的運行時值。

僅當完整的捆綁包標識符相同時,存儲在鑰匙串中的值纔會在應用和應用更新之間共享。

APP1具有一個包標識符BundleIdentifierPrefix1 .com.yourcompany.appname app1.1具有一個包標識符BundleIdentifierPrefix2 .com.yourcompany.appname

由於反向域是相同的,則該應用作爲更新安裝,但由於前綴不同,因此不會共享密鑰鏈值。