Correct way to check for existence of Touch ID on Mac

I have some code to check for the existence of Touch ID on my Mac app and it's causing crashes. One on El Capitain and a crash on macOS Sierra.


Here's my code:


if (NSClassFromString(@"LAContext")) {
     LAContext *myContext = [[LAContext alloc] init];
     NSError *authError = nil;
     if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
          self.enableTouchIDButton.hidden = NO;
     } else {
          self.enableTouchIDButton.hidden = YES;
     }
} else {
     self.enableTouchIDButton.hidden = YES;
}


On El Capitan on a Mac Pro this results in this kind of crash:


Application Specific Information:
Crashing on exception: Unexpected error: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.CoreAuthentication.daemon was invalidated." UserInfo={NSDebugDescription=The connection to service named com.apple.CoreAuthentication.daemon was invalidated.}


Application Specific Backtrace 1:
0   CoreFoundation                      0x00007fff96f7d452 __exceptionPreprocess + 178
1   libobjc.A.dylib                     0x00007fff92b4f73c objc_exception_throw + 48
2   CoreFoundation                      0x00007fff96fe441d +[NSException raise:format:] + 205
3   SharedUtils                         0x00007fff8fa71e1e +[LAErrorHelper raiseExceptionOnError:] + 345
4   LocalAuthentication                 0x00007fff86222a2c -[LAContext initWithExternalizedContext:uiDelegate:] + 485


And on macOS Sierra on a MacBook Pro (without Touch ID):


Crashing on exception: Error Domain=com.apple.LocalAuthentication Code=-1001 "Unknown policy: '1'" UserInfo={NSLocalizedDescription=Unknown policy: '1'}


Application Specific Backtrace 1:
0   CoreFoundation                      0x00007fffacfd848b __exceptionPreprocess + 171
1   libobjc.A.dylib                     0x00007fffc173acad objc_exception_throw + 48
2   CoreFoundation                      0x00007fffad05696d +[NSException raise:format:] + 205
3   SharedUtils                         0x00007fffafea6b63 +[LAErrorHelper raiseExceptionOnError:] + 189
4   LocalAuthentication                 0x00007fffafec1a11 -[LAClient evaluatePolicy:options:uiDelegate:reply:] + 900
5   LocalAuthentication                 0x00007fffafec1ea3 -[LAClient evaluatePolicy:options:reply:] + 99
6   LocalAuthentication                 0x00007fffafec74e9 -[LAContext evaluatePolicy:options:reply:] + 148
7   LocalAuthentication                 0x00007fffafec77e2 -[LAContext evaluatePolicy:options:error:] + 290
8   LocalAuthentication                 0x00007fffafec8dc9 __37-[LAContext canEvaluatePolicy:error:]_block_invoke + 670
9   LocalAuthentication                 0x00007fffafec90fe __37-[LAContext canEvaluatePolicy:error:]_block_invoke.122 + 19
10  libsystem_trace.dylib               0x00007fffc224bc41 _os_activity_initiate + 61
11  LocalAuthentication                 0x00007fffafec8a7f -[LAContext canEvaluatePolicy:error:] + 343



I've tried to find some examples on how to check for this properly on macOS and pretty much nobody is talking about Touch ID on Mac. It's all about iOS. But I know that the SDK is similar between them, so I figured this code should work. It runs fine on my MacBook Pro with macOS Sierra and the TouchBar.


Thanks,

Brendan

Replies

This is a good candidate for contacting our Developer Technical Support folks who can help with this code. I'm not specifically familiar with the LocalAuthenication framework but when I do run that code on my iMac running a current version of macOS Sierra it runs withouth an exception.

Crashing on exception: Error Domain=com.apple.LocalAuthentication Code=-1001 "Unknown policy: '1'" UserInfo={NSLocalizedDescription=Unknown policy: '1'}


So it turned out that this problem with macOS Sierra crashing was due to version 10.12.1. When my beta tester updated to 10.12.3 that error went away.

I ran into a similar problem as well. I couldn't use LAContext's canEvaluatePolicy: to test for the touchID in 10.11.6 since it returns YES which I suspect is due to a bug.

The way to do it is test for NSTouchBar first (which happens be added in the same release as touchID support) then do the rest of the fingerprint reading.


if (NSClassFromString(@"NSTouchBar")) {
    LAContext *authContext = [[LAContext alloc] init];
    BOOL hazIDReader = [authContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
    // The rest of this section of your fingerprint code...
}