TouchID Authenticated but dialog is still shown

1.1k views Asked by At

I'm using TouchID to help users log into my app. Whenever the app is launched the first thing the user sees is the TouchID dialog.

My problem is that if a user launches my app while his finger is already on the home button - the user is immediately authenticated and only then the TouchID dialog is shown. Then - no matter what I do to dismiss the dialog (Enter Password or Cancel) the gray screen is always above my app and I have to restart my iPhone in order to continue working.

How can I solve this?

2

There are 2 answers

0
WDUK On

Ensure you only show the Touch ID dialog when the Application State is Active. If you display it immediately during the launch process (meaning the Application is still technically in an inactive state), then these sorts of issues can occur. This isn't documented, and I found this out the hard way.

For example, to ensure it runs when the application is active, you can check the current application state, and either run it immediately, or when we receive the applicationDidBecomeActive notification. See below for an example:

- (void)setup
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationDidBecomeActive:)
                                                 name:UIApplicationDidBecomeActiveNotification
                                               object:nil];
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    // We need to be in an active state for Touch ID to play nice
    // If we're not, defer the presentation until we are
    if([UIApplication sharedApplication].applicationState == UIApplicationStateActive)
    {
        [self presentTouchID];
    }
    else
    {
        __weak __typeof(self) wSelf = self;
        _onActiveBlock = ^{
            [wSelf presentTouchID];
        };
    }
}

-(void)applicationDidBecomeActive:(NSNotification *)notif
{
    if(_onActiveBlock)
    {
        _onActiveBlock();
        _onActiveBlock = nil;
    }
}

- (void)presentTouchID
{
    _context = [[LAContext alloc] init];
    _context.localizedFallbackTitle = _fallbackTitle;
    [_context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
             localizedReason:_reason
                       reply: ^(BOOL success, NSError *authenticationError)
     {
         // Handle response here
     }];
}
1
Ge Liu On

This issue happens when you use Touch ID immediately after the app launches and change current view controller or window in the reply block of evaluatePolicy:localizedReason:reply:.

Just Wait a while after the availablility check(canEvaluatePolicy:error:) of Touch ID.

Put evaluatePolicy:localizedReason:reply: inside a dispatch_after() like this:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, .5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
                    localizedReason:NSLocalizedString(@"Use Touch ID to Unlock", nil)
                              reply:^(BOOL success, NSError *error) {
                                  if (success) {
                                  }else {
                                      if (error.code == kLAErrorUserCancel) {

                                      }
                                  }
                              }];
});

I've made a sample project as well as a solution here:

https://github.com/RungeZhai/TouchIDIssue

Aviram's answer(godmoney) works as well.