触摸ID导致应用程序变得无法响应

我添加了ios-8的新的touchID API到我的应用程序。 它通常按预期工作,但是当我的手指已经在主页button上时进入应用程序 – API的成功callback被调用,但popup窗口仍然出现在屏幕上。 在按下CANCEL UI后变成不响应。

我也遇到了同样的问题,解决方法是使用高优先级的队列调用Touch ID API,以及延迟:

// 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) { ... } }]; } }); 

当testing我们的应用程序时,我们发现750毫秒的延迟是最佳的,但你的里程可能会有所不同。

更新(03/10/2015):一些iOS开发人员(例如1Password) 报告说iOS 8.2已经解决了这个问题。

尽pipe使用延迟可能会解决问题,但它掩盖了根本原因。 您需要确保在“应用程序状态”处于活动状态时仅显示“触摸ID”对话框。 如果在启动过程中立即显示它(意味着应用程序在技术上仍处于非活动状态),则可能会出现这些显示问题。 这没有logging,我发现这很难。 提供延迟似乎解决了这个问题,因为到那时你的应用程序处于活动状态,但这不是保证。

为了确保它在应用程序处于活动状态时运行,您可以检查当前的应用程序状态,并立即运行它,或者当我们收到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 }]; } 

这个被接受的答案没有解决问题的根本原因:在第一次调用正在进行时第二次调用evaluatePolicy()两次。 所以目前的解决scheme只有偶然的运气,因为一切都取决于时间。

蛮力,直截了当的方法来解决这个问题是一个简单的布尔标志,以防止后续调用发生,直到第一次完成。

 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 { ... } }]; } 

我开始获得“Pending UI机制已经设定”。 也提到了错误,所以我决定看看其他应用程序是否受到影响。 我同时为Touch ID设置了Dropbox和Mint。 果然Touch ID对他们不起作用,他们正在回落到密码。

我重新启动了手机,并重新开始工作,所以看起来Touch ID可能会出错并停止工作。 我在iOS 8.2 btw上。

我想正确的方式来处理这种情况就像那些应用程序,并回退到密码/密码。