I'd like to know if the device is locked when I'm loading my Notification/Today widget, so I can show the widget appropriately. (it's financial, and we don't want to show balances on a locked phone)
On devices with TouchID, I can just try to access the Keychain, and if I get
errSecInteractionNotAllowed
back, it's locked. All good. This doesn't work on devices without touchID (but with a PIN). I've found a few things, which recommend using
[[UIApplication sharedApplication] protectedDataAvailable]
However I don't have [UIApplication sharedApplication]
in a widget.
Any ideas where and how to do this? I just need a yes/no: is the device locked.
Thanks
[UPDATE: here's the code I have]
Getting the filename:
+ (NSString *)lockedDeviceFilename {
NSURL *directoryUrl = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:USER_DEFAULTS_GROUP_NAME];
return [directoryUrl.path stringByAppendingPathComponent:@"security.dummy"];
}
Writing / creating the file (in the app, not the extension:
NSError *error = nil;
NSString *documentPath = [FOOStorageGatekeeper lockedDeviceFilename];
[[NSFileManager defaultManager] removeItemAtPath:documentPath error:&error];
BOOL created = [[NSFileManager defaultManager] createFileAtPath:documentPath
contents:[@"super secret file contents. we only care about the permissions" dataUsingEncoding:NSUTF8StringEncoding]
attributes:@{NSFileProtectionKey : NSFileProtectionComplete}];
Reading:
BOOL isReadable = [[NSFileManager defaultManager] fileExistsAtPath:[FOOStorageGatekeeper lockedDeviceFilename]];
NSLog(@"isReadable? %@", isReadable ? @"YES" : @"NO");
It's always able to read the file, even on a TouchID device with the screen locked. If I look at the attributes, it shows the NSFileProtectionKey is set to NSFileProtectionComplete... but I can STILL READ IT :(
Update: found it. Marking Ian's answer as correct
Create a file with NSFileProtectionComplete
while your app is running and then attempt to access it from your extension. If you can't access it, the screen is locked.
[[NSFileManager defaultManager] createFileAtPath:someFilePath
contents:[@"Lock screen test." dataUsingEncoding:NSUTF8StringEncoding]
attributes:@{NSFileProtectionKey: NSFileProtectionComplete}];
EDIT: Final steps included to complete solution and consolidate answers. (Remaining work provided by Nic Wise.)
NSData *data = [NSData dataWithContentsOfURL:[FOOStorageGatekeeper lockedDeviceUrl] options: NSDataReadingMappedIfSafe error:&error];
if (error != nil && error.code == 257) {
NSLog(@"**** the keychain appears to be locked, using the file method");
return YES;
}
The other method, using errSecInteractionNotAllowed
also works, but only for TouchID devices.
I found the answer (indirectly) here (rego with the iOS dev program most likely needed)
Finally, after 3-4 days of looking, found the answer. It was more in how I was reading the result back. Ian is right: I need to create the file using createFileAtPath, but then read it back using
NSData *data = [NSData dataWithContentsOfURL:[FOOStorageGatekeeper lockedDeviceUrl] options: NSDataReadingMappedIfSafe error:&error];
if (error != nil && error.code == 257) {
NSLog(@"**** the keychain appears to be locked, using the file method");
return YES;
}
The other method, using errSecInteractionNotAllowed
also works, but only for TouchID devices.
I found the answer (indirectly) here (rego with the iOS dev program most likely needed)
I tried that and my file was always readable (in lock screen or not).
I found this document : https://www.apple.com/business/docs/iOS_Security_Guide.pdf
It appeared that the files are locked 10 seconds after the device is locked.
Knowing that, you can create the files from the extensions, and it seems to work.
来源:https://stackoverflow.com/questions/27933666/finding-out-if-the-device-is-locked-from-a-notification-widget