确定iOS设备是否支持TouchID而不设置密码

21

我正在开发一个iOS应用程序,允许用户使用TouchID登录应用程序,但首先他们必须在应用程序内设置密码。问题是,为了显示设置密码选项以启用TouchID登录,我需要检测iOS设备是否支持TouchID。

使用LAContext和canEvaluatePolicy(就像这里的答案所示If Device Supports Touch ID),我能够确定当前设备是否支持TouchID如果用户在其iOS设备上设置了密码。这是我的代码片段(我正在使用Xamarin,因此它是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;
}
如果用户未设置设备密码,则无论设备是否实际支持TouchID,authError都将返回"PasscodeNotSet"错误。
如果用户的设备支持TouchID,则我希望在我的应用程序中始终显示TouchID选项,而不管用户是否在其设备上设置了密码(我只会警告用户首先在其设备上设置密码)。反之亦然,如果用户的设备不支持TouchID,则我显然不想在我的应用程序中显示TouchID选项。
我的问题是,是否有一种好方法可以始终确定iOS设备是否支持TouchID,而不考虑用户是否在其设备上设置了密码?
我能想到的唯一解决方法是确定设备的体系结构(已在Determine if iOS device is 32- or 64-bit中回答),因为TouchID仅支持64位体系结构的设备。但是,我正在寻找是否有更好的方法来完成此操作。
8个回答

20

以下是讨论的结论,在用户没有设置设备密码的情况下,目前无法确定设备是否支持TouchID。

我已经向苹果错误报告中心报告了这个TouchID漏洞。想要关注此问题的人可以在Open Radar上查看:http://www.openradar.me/20342024

感谢@rckoenes的建议 :)

编辑

事实证明,已经有人报告了类似的问题(#18364575)。以下是苹果对该问题的回复:

"工程师已经根据以下信息确定此问题符合预期行为:

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

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

所以......苹果的最终答案是不行。:(

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


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#。

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


3
谢谢您的回答,但恐怕这不是我要寻找的解决方案。据我所知,LAContext类在运行iOS8的所有设备上都可用。但是,在设备运行iOS8但没有TouchID的情况下,if语句将为真,并且NSError仍将返回PasscodeNotSet... 如果我有误,请纠正我 :) - ABVincita
1
确实,但如果您无法使用TouchID,为什么要检测设备是否具有TouchID呢? - rckoenes
2
好的,我的回答是,这是我们团队的设计决定,即使用户还没有设置密码,我们仍然会为所有具有TouchID的设备显示TouchID选项。我们会向用户发出警告,让他们首先在设备上设置密码和指纹,但我们希望展示使用TouchID是可能的。我们可能需要重新评估这个设计决定 - 但无论如何,我想知道是否可能实现这样的事情 :) - ABVincita
2
听起来是个合理的理由,但是有些64位设备没有TouchID,比如iPad Air和iPad Mini retina。你应该向苹果提交一个错误报告,这样他们就可以在SDK的更新中修复这个问题。 - rckoenes
1
啊,对了,我忘记了2013年的iPad Air和iPad mini。所以目前的结论是这样的事情不可能实现。我会尽快向苹果提交一个错误报告。感谢@rckoenes! - ABVincita
显示剩余3条评论

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
        }
    }
}

希望这可以帮到你!

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

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

}

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


这很有帮助,但请包含“#include <sys/sysctl.h>”。 - justinkoh

2
以下是一种方法,可以用来识别设备是否支持 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")
}

流程很简单易懂,只是“let hasTouchId”可以改名为“let deviceHasBiometry”。 - Naishta

0

iOS 11+版本可以使用LAContextbiometryType: LABiometryType。更多信息请参阅苹果文档:

/// 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
}

0

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接