Skip to content

Commit

Permalink
fix(iOS): Don't reset the storage when the manifest file cannot be re…
Browse files Browse the repository at this point in the history
…ad because of iOS data protection (#270)

This is to distinguish "manifest file does not exist or is corrupted" and "have no access to the manifest file yet" cases.

Starting with an empty dictionary is a reasonable fallback in case the manifest does not exist or cannot be parsed because of being corrupted or incompatible. However doing so might lead to unnecessary data loss when the app simply has no access to its documents yet due to iOS data protection (if enabled and when the app launches while the device is locked due to e.g. geofencing, silent notification, external accessory, etc).
  • Loading branch information
aleh authored and tido64 committed Jan 12, 2020
1 parent 9aad474 commit 36e9a12
Showing 1 changed file with 22 additions and 5 deletions.
27 changes: 22 additions & 5 deletions ios/RNCAsyncStorage.m
Original file line number Diff line number Diff line change
Expand Up @@ -343,16 +343,33 @@ - (NSDictionary *)_ensureSetup
}
RCTHasCreatedStorageDirectory = YES;
}

if (!_haveSetup) {
NSDictionary *errorOut;
NSDictionary *errorOut = nil;
NSString *serialized = RCTReadFile(RCTGetManifestFilePath(), RCTManifestFileName, &errorOut);
_manifest = serialized ? RCTJSONParseMutable(serialized, &error) : [NSMutableDictionary new];
if (error) {
RCTLogWarn(@"Failed to parse manifest - creating new one.\n\n%@", error);
_manifest = [NSMutableDictionary new];
if (!serialized) {
if (errorOut) {
// We cannot simply create a new manifest in case the file does exist but we have no access to it.
// This can happen when data protection is enabled for the app and we are trying to read the manifest
// while the device is locked. (The app can be started by the system even if the device is locked due to
// e.g. a geofence event.)
RCTLogError(@"Could not open the existing manifest, perhaps data protection is enabled?\n\n%@", errorOut);
return errorOut;
} else {
// We can get nil without errors only when the file does not exist.
RCTLogTrace(@"Manifest does not exist - creating a new one.\n\n%@", errorOut);
_manifest = [NSMutableDictionary new];
}
} else {
_manifest = RCTJSONParseMutable(serialized, &error);
if (!_manifest) {
RCTLogError(@"Failed to parse manifest - creating a new one.\n\n%@", error);
_manifest = [NSMutableDictionary new];
}
}
_haveSetup = YES;
}

return nil;
}

Expand Down

0 comments on commit 36e9a12

Please sign in to comment.