@@ -79,13 +79,24 @@ static void RCTAppendError(NSDictionary *error, NSMutableArray<NSDictionary *> *
79
79
return nil ;
80
80
}
81
81
82
+ // DO NOT USE
83
+ // This is used internally to migrate data from the old file location to the new one.
84
+ // Please use `RCTCreateStorageDirectoryPath` instead
85
+ static NSString *RCTCreateStorageDirectoryPath_deprecated (NSString *storageDir) {
86
+ NSString *storageDirectoryPath;
87
+ #if TARGET_OS_TV
88
+ storageDirectoryPath = NSSearchPathForDirectoriesInDomains (NSCachesDirectory, NSUserDomainMask, YES ).firstObject ;
89
+ #else
90
+ storageDirectoryPath = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES ).firstObject ;
91
+ #endif
92
+ storageDirectoryPath = [storageDirectoryPath stringByAppendingPathComponent: storageDir];
93
+ return storageDirectoryPath;
94
+ }
95
+
82
96
static NSString *RCTCreateStorageDirectoryPath (NSString *storageDir) {
83
- NSString *storageDirectoryPath;
84
- #if TARGET_OS_TV
85
- storageDirectoryPath = NSSearchPathForDirectoriesInDomains (NSCachesDirectory, NSUserDomainMask, YES ).firstObject ;
86
- #else
87
- storageDirectoryPath = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES ).firstObject ;
88
- #endif
97
+ // We should use the "Application Support/[bundleID]" folder for persistent data storage that's hidden from users
98
+ NSString *storageDirectoryPath = NSSearchPathForDirectoriesInDomains (NSApplicationSupportDirectory, NSUserDomainMask, YES ).firstObject ;
99
+ storageDirectoryPath = [storageDirectoryPath stringByAppendingPathComponent: [[NSBundle mainBundle ] bundleIdentifier ]]; // Per Apple's docs, all app content in Application Support must be within a subdirectory of the app's bundle identifier
89
100
storageDirectoryPath = [storageDirectoryPath stringByAppendingPathComponent: storageDir];
90
101
return storageDirectoryPath;
91
102
}
@@ -102,7 +113,7 @@ static void RCTAppendError(NSDictionary *error, NSMutableArray<NSDictionary *> *
102
113
103
114
static NSString *RCTCreateManifestFilePath (NSString *storageDirectory)
104
115
{
105
- return [RCTCreateStorageDirectoryPath ( storageDirectory) stringByAppendingPathComponent: RCTManifestFileName];
116
+ return [storageDirectory stringByAppendingPathComponent: RCTManifestFileName];
106
117
}
107
118
108
119
static NSString *RCTGetManifestFilePath ()
@@ -194,58 +205,61 @@ static void RCTStorageDirectoryMigrationLogError(NSString *reason, NSError *erro
194
205
RCTLogWarn (@" %@ : %@ " , reason, error ? error.description : @" " );
195
206
}
196
207
197
- static void RCTStorageDirectoryCleanupOld ()
208
+ static void RCTStorageDirectoryCleanupOld (NSString *oldDirectoryPath )
198
209
{
199
210
NSError *error;
200
- if (![[NSFileManager defaultManager ] removeItemAtPath: RCTCreateStorageDirectoryPath (RCTOldStorageDirectory) error: &error]) {
211
+ if (![[NSFileManager defaultManager ] removeItemAtPath: oldDirectoryPath error: &error]) {
201
212
RCTStorageDirectoryMigrationLogError (@" Failed to remove old storage directory during migration" , error);
202
213
}
203
214
}
204
215
205
- static void RCTStorageDirectoryMigrate ()
216
+ static void RCTStorageDirectoryMigrate (NSString *oldDirectoryPath, NSString *newDirectoryPath, BOOL shouldCleanupOldDirectory )
206
217
{
207
218
NSError *error;
208
219
// Migrate data by copying old storage directory to new storage directory location
209
- if (![[NSFileManager defaultManager ] copyItemAtPath: RCTCreateStorageDirectoryPath (RCTOldStorageDirectory) toPath: RCTGetStorageDirectory () error: &error]) {
220
+ if (![[NSFileManager defaultManager ] copyItemAtPath: oldDirectoryPath toPath: newDirectoryPath error: &error]) {
210
221
RCTStorageDirectoryMigrationLogError (@" Failed to copy old storage directory to new storage directory location during migration" , error);
211
- } else {
222
+ } else if (shouldCleanupOldDirectory) {
212
223
// If copying succeeds, remove old storage directory
213
- RCTStorageDirectoryCleanupOld ();
224
+ RCTStorageDirectoryCleanupOld (oldDirectoryPath );
214
225
}
215
226
}
216
227
217
228
/* *
218
229
* This check is added to make sure that anyone coming from pre-1.2.2 does not lose cached data.
219
- * Data is migrated from the "RNCAsyncLocalStorage_V1" directory to the "RCTAsyncLocalStorage_V1" directory.
230
+ * Check that data is migrated from the old location to the new location
231
+ * fromStorageDirectory: the directory where the older data lives
232
+ * toStorageDirectory: the directory where the new data should live
233
+ * shouldCleanupOldDirectoryAndOverwriteNewDirectory: YES if we should delete the old directory's contents and overwrite the new directory's contents during the migration to the new directory
220
234
*/
221
- static void RCTStorageDirectoryMigrationCheck ()
235
+ static void RCTStorageDirectoryMigrationCheck (NSString *fromStorageDirectory, NSString *toStorageDirectory, BOOL shouldCleanupOldDirectoryAndOverwriteNewDirectory )
222
236
{
223
- static dispatch_once_t onceToken;
224
- dispatch_once (&onceToken, ^{
225
- NSError *error;
226
- BOOL isDir;
227
- // If the old directory exists, it means we may need to migrate old data to the new directory
228
- if ([[NSFileManager defaultManager ] fileExistsAtPath: RCTCreateStorageDirectoryPath (RCTOldStorageDirectory) isDirectory: &isDir] && isDir) {
229
- // Check if the new storage directory location already exists
230
- if ([[NSFileManager defaultManager ] fileExistsAtPath: RCTGetStorageDirectory ()]) {
231
- // If new storage location exists, check if the new storage has been modified sooner
232
- if ([RCTManifestModificationDate (RCTGetManifestFilePath ()) compare: RCTManifestModificationDate (RCTCreateManifestFilePath (RCTOldStorageDirectory))] == 1 ) {
233
- // If new location has been modified more recently, simply clean out old data
234
- RCTStorageDirectoryCleanupOld ();
237
+ NSError *error;
238
+ BOOL isDir;
239
+ NSFileManager *fileManager = [NSFileManager defaultManager ];
240
+ // If the old directory exists, it means we may need to migrate old data to the new directory
241
+ if ([fileManager fileExistsAtPath: fromStorageDirectory isDirectory: &isDir] && isDir) {
242
+ // Check if the new storage directory location already exists
243
+ if ([fileManager fileExistsAtPath: toStorageDirectory]) {
244
+ // If new storage location exists, check if the new storage has been modified sooner in which case we may want to cleanup the old location
245
+ if ([RCTManifestModificationDate (RCTCreateManifestFilePath (toStorageDirectory)) compare: RCTManifestModificationDate (RCTCreateManifestFilePath (fromStorageDirectory))] == 1 ) {
246
+ // If new location has been modified more recently, simply clean out old data
247
+ if (shouldCleanupOldDirectoryAndOverwriteNewDirectory) {
248
+ RCTStorageDirectoryCleanupOld (fromStorageDirectory);
249
+ }
250
+ } else if (shouldCleanupOldDirectoryAndOverwriteNewDirectory) {
251
+ // If old location has been modified more recently, remove new storage and migrate
252
+ if (![fileManager removeItemAtPath: toStorageDirectory error: &error]) {
253
+ RCTStorageDirectoryMigrationLogError (@" Failed to remove new storage directory during migration" , error);
235
254
} else {
236
- // If old location has been modified more recently, remove new storage and migrate
237
- if (![[NSFileManager defaultManager ] removeItemAtPath: RCTGetStorageDirectory () error: &error]) {
238
- RCTStorageDirectoryMigrationLogError (@" Failed to remove new storage directory during migration" , error);
239
- } else {
240
- RCTStorageDirectoryMigrate ();
241
- }
255
+ RCTStorageDirectoryMigrate (fromStorageDirectory, toStorageDirectory, shouldCleanupOldDirectoryAndOverwriteNewDirectory);
242
256
}
243
- } else {
244
- // If new storage location doesn't exist, migrate data
245
- RCTStorageDirectoryMigrate ();
246
257
}
258
+ } else {
259
+ // If new storage location doesn't exist, migrate data
260
+ RCTStorageDirectoryMigrate (fromStorageDirectory, toStorageDirectory, shouldCleanupOldDirectoryAndOverwriteNewDirectory);
247
261
}
248
- });
262
+ }
249
263
}
250
264
251
265
#pragma mark - RNCAsyncStorage
@@ -269,7 +283,13 @@ - (instancetype)init
269
283
if (!(self = [super init ])) {
270
284
return nil ;
271
285
}
272
- RCTStorageDirectoryMigrationCheck ();
286
+
287
+ // First migrate our deprecated path "Documents/.../RNCAsyncLocalStorage_V1" to "Documents/.../RCTAsyncLocalStorage_V1"
288
+ RCTStorageDirectoryMigrationCheck (RCTCreateStorageDirectoryPath_deprecated (RCTOldStorageDirectory), RCTCreateStorageDirectoryPath_deprecated (RCTStorageDirectory), YES );
289
+
290
+ // Then migrate what's in "Documents/.../RCTAsyncLocalStorage_V1" to "Application Support/[bundleID]/RCTAsyncLocalStorage_V1"
291
+ RCTStorageDirectoryMigrationCheck (RCTCreateStorageDirectoryPath_deprecated (RCTStorageDirectory), RCTCreateStorageDirectoryPath (RCTStorageDirectory), NO );
292
+
273
293
return self;
274
294
}
275
295
@@ -346,7 +366,7 @@ - (NSDictionary *)_ensureSetup
346
366
347
367
if (!_haveSetup) {
348
368
NSDictionary *errorOut = nil ;
349
- NSString *serialized = RCTReadFile (RCTGetManifestFilePath (), RCTManifestFileName, &errorOut);
369
+ NSString *serialized = RCTReadFile (RCTCreateStorageDirectoryPath ( RCTGetManifestFilePath () ), RCTManifestFileName, &errorOut);
350
370
if (!serialized) {
351
371
if (errorOut) {
352
372
// We cannot simply create a new manifest in case the file does exist but we have no access to it.
@@ -377,7 +397,7 @@ - (NSDictionary *)_writeManifest:(NSMutableArray<NSDictionary *> **)errors
377
397
{
378
398
NSError *error;
379
399
NSString *serialized = RCTJSONStringify (_manifest, &error);
380
- [serialized writeToFile: RCTGetManifestFilePath () atomically: YES encoding: NSUTF8StringEncoding error: &error];
400
+ [serialized writeToFile: RCTCreateStorageDirectoryPath ( RCTGetManifestFilePath () ) atomically: YES encoding: NSUTF8StringEncoding error: &error];
381
401
NSDictionary *errorOut;
382
402
if (error) {
383
403
errorOut = RCTMakeError (@" Failed to write manifest file." , error, nil );
0 commit comments