21

I'm currently developing an iOS app that enables users to log in to the app using TouchID, but firstly they must set up a password inside the app first. Problem is, to show the setup password option to enable the TouchID login, I need to detect if the iOS device supports TouchID.

Using the LAContext and canEvaluatePolicy (like the answers in here If Device Supports Touch ID), I am able to determine whether the current device supports TouchID if the user has set up passcode on their iOS device. Here is a my code snippet (I'm using Xamarin, so it's in C#):

static bool DeviceSupportsTouchID () 
{
    if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
    {
        var context = new LAContext();
        NSError authError;
        bool touchIDSetOnDevice = context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out authError);

        return (touchIDSetOnDevice || (LAStatus) Convert.ToInt16(authError.Code) != LAStatus.TouchIDNotAvailable);
    }

    return false;
}

If the user has not set up the device passcode, the authError will just return "PasscodeNotSet" error regardless of whether the device actually supports TouchID or not.

If the user's device supports TouchID, I want to always show the TouchID option in my app regardless of whether the user has set up passcode on their device (I will just warn the user to setup passcode on their device first). Vice versa, if the user's device doesn't support TouchID, I obviously don't want to show the TouchID option in my app.

So my question is, is there a nice way to consistently determine whether an iOS device supports TouchID regardless of whether the user has set up passcode on their device?

The only workaround I can think of is to determine the architecture of the device (which is answered in Determine if iOS device is 32- or 64-bit), as TouchID is only supported on devices with 64-bit architecture. However, I'm looking if there's any nicer way to do this.

4

8 回答 8

20

总结下面的讨论,当用户没有在他们的设备上设置密码时,暂时无法确定设备是否真的支持 TouchID。

我已经在 Apple 错误报告器上报告了这个 TouchID 缺陷。那些想关注这个问题的人可以在 Open Radar 上看到它:http ://www.openradar.me/20342024

感谢@rckoenes 的输入:)

编辑

原来有人已经报告了类似的问题(#18364575)。以下是 Apple 对此问题的回复:

“工程部门已根据以下信息确定此问题的行为符合预期:

如果未设置密码,您将无法检测到 Touch ID 的存在。设置密码后,canEvaluatePolicy 最终将返回 LAErrorTouchIDNotAvailable 或 LAErrorTouchIdNotEnrolled,您将能够检测到 Touch ID 的存在/状态。

如果用户在带有 Touch ID 的手机上禁用了密码,他们知道他们将无法使用 Touch ID,因此应用程序不需要检测 Touch ID 的存在或推广基于 Touch ID 的功能。"

所以..... Apple的最终答案是No。:(

注意:来自报告此问题的人的类似 StackOverflow 问题 - > iOS8 检查设备是否具有 Touch ID (想知道为什么我之前没有找到这个问题,尽管我进行了广泛的搜索......)

于 2015-03-30T05:06:30.517 回答
14

检测TouchID是否可用的正确方法:

BOOL hasTouchID = NO;
// if the LAContext class is available
if ([LAContext class]) {
    LAContext *context = [LAContext new];
    NSError *error = nil;
    hasTouchId = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
}

抱歉,它在 Objective-C 中,您可能需要将其翻译为 C#。

您应该避免检查系统版本,而只检查类或方法是否可用。

于 2015-03-26T13:40:44.017 回答
7

我知道这是去年的一个问题,但这个解决方案不能满足您的需求?(SWIFT代码)

if #available(iOS 8.0, *) {
    var error: NSError?
    let hasTouchID = LAContext().canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error)

    //Show the touch id option if the device has touch id hardware feature (even if the passcode is not set or touch id is not enrolled)
    if(hasTouchID || (error?.code != LAError.TouchIDNotAvailable.rawValue)) {
        touchIDContentView.hidden = false
    } 
}

然后,当用户按下按钮使用 touch id 登录时:

@IBAction func loginWithTouchId() {
    let context = LAContext()

    var error: NSError?
    let reasonString = "Log in with Touch ID"

    if (context.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error)) {
        [context.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: reasonString, reply: { (success: Bool, evalPolicyError: NSError?) -> Void in
            //Has touch id. Treat the success boolean
        })]
    } else { 
        //Then, if the user has touch id but is not enrolled or the passcode is not set, show a alert message
        switch error!.code{

        case LAError.TouchIDNotEnrolled.rawValue:
            //Show alert message to inform that touch id is not enrolled
            break

        case LAError.PasscodeNotSet.rawValue:
            //Show alert message to inform that passcode is not set
            break

        default:
            // The LAError.TouchIDNotAvailable case.
            // Will not catch here, because if not available, the option will not visible
        }
    }
}

希望能帮助到你!

于 2016-06-21T20:11:52.547 回答
4

对于 Objective C
它适用于所有设备,无需检查设备版本。

- (void)canAuthenticatedByTouchID{
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = touchIDRequestReason;

if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
 }else{
    switch (authError.code) {
        case kLAErrorTouchIDNotAvailable:
            [labelNotSupportTouchID setHidden:NO];
            [switchBtn setHidden:YES];
            [labelEnableTouchid setHidden:YES];
            static dispatch_once_t onceToken;
            dispatch_once(&onceToken, ^{
                [self showAlertMessage:@"EyeCheck Pro" message:@"Device does not support Touch ID Service."];
            });

            break;
    }
  }
}
于 2017-04-27T11:52:40.533 回答
3

以下是您可以识别设备是否支持 Touch Id 或 Face ID 的方法

open class LocalAuth: NSObject {

    public static let shared = LocalAuth()

    private override init() {}

    var laContext = LAContext()

    func canAuthenticate() -> Bool {
        var error: NSError?
        let hasTouchId = laContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)
        return hasTouchId
    }

    func hasTouchId() -> Bool {
        if canAuthenticate() && laContext.biometryType == .touchID {
            return true
        }
        return false
    }

    func hasFaceId() -> Bool {
        if canAuthenticate() && laContext.biometryType == .faceID {
            return true
        }
        return false
    }

}

以下是上述共享代码的用法

if LocalAuth.shared.hasTouchId() {
    print("Has Touch Id")
} else if LocalAuth.shared.hasFaceId() {
    print("Has Face Id")
} else {
    print("Device does not have Biometric Authentication Method")
}
于 2019-07-05T12:07:16.433 回答
3

这是确定设备是否具有物理触摸 id 传感器的一种有点乏味的方法。

+ (BOOL)isTouchIDExist {
if(![LAContext class]) //Since this mandotory class is not there, that means there is no physical touch id.
    return false;

//Get the current device model name
size_t size;
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
char *model = malloc(size);
sysctlbyname("hw.machine", model, &size, NULL, 0);
NSString *deviceModel = [NSString stringWithCString:model encoding:NSUTF8StringEncoding];

//Devices that does not support touch id
NSArray *deviceModelsWithoutTouchID = [[NSArray alloc]
                                       initWithObjects:
                                       @"iPhone1,1", //iPhone
                                       @"iPhone1,2", //iPhone 3G
                                       @"iPhone2,1", //iPhone 3GS
                                       @"iPhone3,1", //iPhone 4
                                       @"iPhone3,2",
                                       @"iPhone3,3",
                                       @"iPhone4,1", //iPhone 4S
                                       @"iPhone5,1", //iPhone 5
                                       @"iPhone5,2",
                                       @"iPhone5,3", //iPhone 5C
                                       @"iPhone5,4",
                                       @"iPod1,1", //iPod
                                       @"iPod2,1",
                                       @"iPod3,1",
                                       @"iPod4,1",
                                       @"iPod5,1",
                                       @"iPod7,1",
                                       @"iPad1,1", //iPad
                                       @"iPad2,1", //iPad 2
                                       @"iPad2,2",
                                       @"iPad2,3",
                                       @"iPad2,4",// iPad mini 1G
                                       @"iPad2,5",
                                       @"iPad2,5",
                                       @"iPad2,7",
                                       @"iPad3,1", //iPad 3
                                       @"iPad3,2",
                                       @"iPad3,3",
                                       @"iPad3,4", //iPad 4
                                       @"iPad3,5",
                                       @"iPad3,6",
                                       @"iPad4,1", //iPad Air
                                       @"iPad4,2",
                                       @"iPad4,3",
                                       @"iPad4,4", //iPad mini 2
                                       @"iPad4,5",
                                       @"iPad4,6",
                                       @"iPad4,7",
                                       nil];

return ![deviceModelsWithoutTouchID containsObject:deviceModel];

}

参考: https ://www.theiphonewiki.com/wiki/Models https://en.wikipedia.org/wiki/IOS

于 2015-10-27T20:33:53.787 回答
0

对于 iOS 11+,对于上下文错误,您可以检查kLAErrorBiometryNotAvailable

于 2022-01-05T06:33:21.910 回答
0

对于 iOS 11+ ,您可以使用biometryType: LABiometryType. LAContext更多来自 Apple 文档:

/// Indicates the type of the biometry supported by the device.
///
/// @discussion  This property is set only when canEvaluatePolicy succeeds for a biometric policy.
///              The default value is LABiometryTypeNone.
@available(iOS 11.0, *)
open var biometryType: LABiometryType { get }

@available(iOS 11.0, *)
public enum LABiometryType : Int {

    /// The device does not support biometry.
    @available(iOS 11.2, *)
    case none

    /// The device does not support biometry.
    @available(iOS, introduced: 11.0, deprecated: 11.2, renamed: "LABiometryType.none")
    public static var LABiometryNone: LABiometryType { get }

    /// The device supports Touch ID.
    case touchID

    /// The device supports Face ID.
    case faceID
}
于 2018-09-12T10:17:46.257 回答