Peter Zhang Peter Zhang - 3 months ago 24
iOS Question

Can't read from iOS app sandbox when handling local action from lock screen

To handle local actions, my app needs to read a file to decide what to do. This works fine when the local action is coming from a user interacting with a banner or an alert. It also works when the local action is coming from a user interacting with a notification on the lock screen, as long as the app is currently backgrounded (as opposed to completely off).

However, if the app is completely off, and the user tries to interact with a notification on the lock screen, I get an error saying

"The file ... couldn’t be opened because you don’t have permission to view it."


Does anyone know what might be going wrong, and how I could go about getting access to previously saved files in this situation?

As an example, the below code will work just fine, except when handleActionWithIdentifier is called because of a notification on the lock screen, and the app is off.

// Handle local actionable notifications
- (void)application:(UIApplication *) application handleActionWithIdentifier: (NSString *) identifier forLocalNotification: (UILocalNotification *) notification completionHandler: (void (^)()) completionHandler
{
//NSString *test = @"hello world";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:@"test"];
//[test writeToFile:appFile atomically:YES encoding:NSUTF8StringEncoding error:nil];

NSLog(@"*********************");
NSLog(@"trying to read test from handle action");
NSLog(@"trying to read test from this location: %@", appFile);
NSError *testerror;
NSStringEncoding testencoding;
NSString *testString = [NSString stringWithContentsOfFile:appFile usedEncoding:&testencoding error:&testerror];
if (testerror) {
NSLog(@"Failed to read storage file: %@", testerror);
} else if (testencoding != NSUTF8StringEncoding) {
NSLog(@"Incorect encoding of storage file.");
} else {
NSLog(testString);
}
NSLog(@"*********************");
}


The full output of the above code when the error occurs is included below:

Aug 11 14:39:42 iPhone Tandem[614] <Warning>: *********************
Aug 11 14:39:42 iPhone Tandem[614] <Warning>: trying to read test from handle action
Aug 11 14:39:42 iPhone Tandem[614] <Warning>: trying to read test from this location: /var/mobile/Containers/Data/Application/2C31417E-EF8E-4E0A-AC37-F4CB5BE9A4A5/Documents/test
Aug 11 14:39:42 iPhone Tandem[614] <Warning>: Failed to read storage file: Error Domain=NSCocoaErrorDomain Code=257 "The file “test” couldn’t be opened because you don’t have permission to view it." UserInfo={NSFilePath=/var/mobile/Containers/Data/Application/2C31417E-EF8E-4E0A-AC37-F4CB5BE9A4A5/Documents/test, NSUnderlyingError=0x145577d30 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
Aug 11 14:39:42 iPhone Tandem[614] <Warning>: *********************


The same problem occurs if I try to read the file from
application: didFinishLaunching:
as well.

Answer

You should check the file protection attribute. My guess would be that it is set to NSFileProtectionComplete or NSFileProtectionCompleteUnlessOpen which means the file cannot be read while the device is locked. You can set the attribute to NSFileProtectionNone to read the file while the device is locked, but be aware that it will not be stored in an encrypted state.

See: https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSFileManager_Class/#//apple_ref/doc/constant_group/File_Protection_Values

Comments