In iOS 10, if TouchID is used and the user has too many attempts (such as using the wrong finger), the OS locks the user out until they enter their PIN. For applications, this means that the canEvaluatePolicy call on the LAContext class will always return False until the user "unlocks" TouchID with their PIN.

In iOS 10, if TouchID is used and the user has too many attempts (such as using the wrong finger), the OS locks the user out until they enter their PIN. For applications, this means that the canEvaluatePolicy call on the LAContext class will always return False until the user "unlocks" TouchID with their PIN.

The problem is being able to detect if this is the reason why the call returns False, which can be done only through examining the Code property on the error parameter in the canEvaluatePolicy call. The docs show that the error parameter is an NSErrorPointer:

https://developer.apple.com/reference/localauthentication/lacontext/1514149-canevaluatepolicy

i.e. a pointer to an NSError, so in Delphi I have the method declared like this:

function canEvaluatePolicy(policy: LAPolicy; error: Pointer): Boolean; cdecl;

Except that I'm having trouble with how to access the returned error. Simply dereferencing the parameter doesn't work (which I wouldn't expect it to anyway), however using the Wrap method of TNSError also does not work (the former locks up the app, the latter causes a crash). Some example code:

var
LPointer: Pointer;
LError: NSError;
LCode: Int64;
begin
Result := FContext.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, LPointer);
if LPointer <> nil then
begin
LError := TNSError.Wrap(LPointer); // PNSError(LPointer)^; // Neither way works
LCode := LError.code;
if LCode <> 0 then
// Take action here
end;
end;

Any ideas on how to solve this?

https://developer.apple.com/reference/localauthentication/lacontext/1514149-canevaluatepolicy

Comments

  1. var
    LPointer: PPointer; // or ^ID as that's more explicit
    //...
    LError := TNSError.Wrap(LPointer^);

    ReplyDelete
  2. Chris Rolliston OK, that has me a step closer. I can access the error parameter as an NSError, but now I have an AV when the method exits..

    ReplyDelete
  3. Chris Rolliston Never mind.. worked it out, by doing the following (which is consistent with other places in the RTL/FMX):

    Method declaration:

    function canEvaluatePolicy(policy: LAPolicy; error: PPointer): Boolean; cdecl;

    Code:

    var
    LPointer: Pointer;
    LError: NSError;
    begin
    Result := FContext.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, @LPointer);
    LError := TNSError.Wrap(LPointer);
    if LError.code <> 0 then
    // Take action
    end;

    ReplyDelete

Post a Comment