Touch ID, вызывающий приложение, становится невосприимчивым

Я добавил iOS-8 новый touchID API для своего приложения. Обычно он работает так, как ожидалось, но при входе в приложение, когда мой палец уже включен на домашней кнопке - вызывается обратный вызов API, но всплывающее окно по-прежнему появляется на экране. после нажатия CANCEL UI становится невосприимчивым.

Ответ 1

Я также столкнулся с той же проблемой, и решение заключалось в вызове вызова API Touch ID с использованием очереди с высоким приоритетом, а также задержки:

// Touch ID must be called with a high priority queue, otherwise it might fail.
// Also, a dispatch_after is required, otherwise we might receive "Pending UI mechanism already set."
dispatch_queue_t highPriorityQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.75 * NSEC_PER_SEC), highPriorityQueue, ^{
  LAContext *context = [[LAContext alloc] init];
  NSError *error = nil;

  // Check if device supports TouchID
  if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
      // TouchID supported, show it to user
      [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
              localizedReason:@"Unlock Using Touch ID"
                        reply:^(BOOL success, NSError *error) {
                            if (success) {
                                // This action has to be on main thread and must be synchronous
                                dispatch_async(dispatch_get_main_queue(), ^{
                                    ...
                                });
                            }
                            else if (error) {
                                ...
                            }
                        }];
  }
});

При тестировании нашего приложения мы обнаружили, что оптимальная продолжительность 750 мс, но ваш пробег может отличаться.

Обновление (03/10/2015): Некоторые разработчики iOS, например, 1Password, сообщают, что iOS 8.2 окончательно исправили этот вопрос.

Ответ 2

В то время как использование задержки может потенциально решить проблему, она маскирует основную причину. Вам нужно убедиться, что вы только показываете диалог Touch ID, когда состояние приложения активно. Если вы отобразите его сразу во время запуска (это означает, что приложение по-прежнему технически находится в неактивном состоянии), тогда могут возникать такие проблемы с отображением. Это не документировано, и я нашел это трудным путем. Предоставление задержки, похоже, исправляет ее, потому что к тому времени приложение находится в активном состоянии, но это не гарантировано.

Чтобы гарантировать, что он будет запущен, когда приложение будет активным, вы можете проверить текущее состояние приложения и сразу запустить его или получить уведомление applicationDidBecomeActive. Ниже приведен пример:

- (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
     }];
}

Ответ 3

Этот принятый ответ не затрагивает основную причину проблемы: дважды ссылается на valuePolicy(), второй раз, когда выполняется первый вызов. Таким образом, текущее решение работает иногда просто удачей, поскольку все зависит от времени.

С помощью грубой силы, простой способ обойти эту проблему - простой логический флаг, чтобы предотвратить последующие вызовы до первого завершения.

AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
if ( NSClassFromString(@"LAContext") && ! delegate.touchIDInProgress ) {
    delegate.touchIDInProgress = YES;
    LAContext *localAuthenticationContext = [[LAContext alloc] init];
    __autoreleasing NSError *authenticationError;
    if ([localAuthenticationContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authenticationError]) {
        [localAuthenticationContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:kTouchIDReason reply:^(BOOL success, NSError *error) {
            delegate.touchIDInProgress = NO;
            if (success) {
                ...
            } else {
                ...
            }
        }];
    }

Ответ 4

Я начал получать уже установленный механизм ожидающего пользовательского интерфейса. ошибка упоминалась также, поэтому я решил посмотреть, были ли затронуты другие приложения. У меня установлены Dropbox и Mint для Touch ID. Разумеется, Touch ID не работал и для них, и они возвращались к паролям.

Я перезагрузил свой телефон, и он снова начал работать, поэтому казалось бы, что Touch ID может исправить ошибки и перестать работать. Я нахожусь на iOS 8,2 бит.

Я предполагаю, что правильный способ справиться с этим состоянием - это то же самое, что и приложения, и возврат к паролю/паролю.