确定受 Touch ID 保护的钥匙串项是否存在?

Determine if Touch ID-Protected Keychain Item Exists?

有没有一种方法可以使用 Touch ID 访问控制 来确定是否已在 iOS 钥匙串中设置了一个项目(密码、令牌等) =25=] 提示用户输入 Touch ID?我们需要在执行操作之前确定凭据是否已保存到钥匙串(具有 Touch ID 保护),但我们不想用 Touch ID 提示打扰用户。

我试过以下...

NSMutableDictionary *query = ...
query[(__bridge id)kSecUseNoAuthenticationUI] = (__bridge id)kCFBooleanTrue;

OSStatus opStatus = SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL);

...

但是,调用此代码时,用户仍会看到 Touch ID 提示。我们不希望 ANYTHING 显示在 UI 上,只希望在 OSStatus 中返回一个错误如果需要 Touch ID

有什么想法吗?

NSDictionary *query = @{
                        (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
                        (__bridge id)kSecAttrService: @"SampleService",
                        (__bridge id)kSecUseNoAuthenticationUI: @YES
                        };

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    CFTypeRef dataTypeRef = NULL;
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)(query), &dataTypeRef);
    if (status == errSecInteractionNotAllowed) {
        NSLog(@"ITEM EXIST");
    } else if (status == errSecItemNotFound) {
        NSLog(@"ITEM DOES NOT EXIST");
    } else {
        NSLog(@"status: %@", @(status));
    }
});

基于 neoneye 的代码和 Swift 3. 我添加了 errSecAuthFailed。

    query[kSecClass as String] : kSecClassGenericPassword,
    query[kSecAttrService as String] : "serviceName"    
    query[kSecUseAuthenticationUI as String] = kSecUseAuthenticationUIFail

    DispatchQueue.global().async {

        var result : AnyObject?
        let status = SecItemCopyMatching(query as CFDictionary, &result)

        if status == errSecInteractionNotAllowed {

            DispatchQueue.main.async {

                // item exists
            }
        } else if status == errSecAuthFailed {

            DispatchQueue.main.async {

                // item exists but someone removed the touch id or passcode
            }
        } else if status == errSecItemNotFound {

            DispatchQueue.main.async {

                // it does not exist
            }
        } else {

            DispatchQueue.main.async {

                // another OSStatus
            }
        }
    }