如何以编程方式检查“Face ID”和“Touch ID”的支持。

53

我已经为我的应用程序安全目的集成了LocalAuthentication,它支持基于'Touch Id'的支持。但现在,苹果最近还添加了基于'Face Id'的身份验证方式。

我该如何检查设备支持哪种类型的身份验证方式。Touch Id还是Face Id?


你能帮我解决这个问题吗?https://dev59.com/nlMH5IYBdhLWcg3wzzAe - Sagar
15个回答

76

我一直在努力让这个工作,发现我需要使用单个LAContext实例,并且需要调用LAContextInstance.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil)来获取生物识别类型之前。 这是我的最终代码,支持旧版iOS:

import LocalAuthentication

static func biometricType() -> BiometricType {
    let authContext = LAContext()
    if #available(iOS 11, *) {
        let _ = authContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil)
        switch(authContext.biometryType) {
        case .none:
            return .none
        case .touchID:
            return .touch
        case .faceID:
            return .face
        }
    } else {
        return authContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) ? .touch : .none
    }
}

enum BiometricType {
    case none
    case touch
    case face
}

1
谢谢。正是我想要的 :) - Sethmr
10
biometryType的文档说明:仅当生物识别策略的canEvaluatePolicy成功时,才设置此属性。因此,如果canEvaluatePolicy失败(例如touchid/faceid完全未激活或按应用程序禁用),则biometricType()返回.none。因此,biometricType()的检查不是硬件是否可用,而是应用程序是否可以访问硬件。 - Valeriy Van
1
@ValeriyVan 你有没有想到一种检查设备硬件可用性的方法?似乎每个人都说biometricType是答案,但正如你所说,如果你只是想向用户显示一个按钮,上面写着“Face ID”或“Touch ID”,以便用户可以授权其中之一 当设备尚未通过生物识别技术进行身份验证时,这实际上是错误的答案。 - SAHM
2
@SAHM,实际上我没有找到比检查设备类型更好的方法。这是一种不太好的方式,因为它不具有未来性。希望苹果会更新API以解决这个问题。 - Valeriy Van
1
这个问题是正确的,应该被选择为已接受的。 - swift2geek
显示剩余4条评论

52

使用Xcode 9,请查看LocalAuthentication->LAContext->LABiometryType

LABiometryType是一个枚举类型,其值如附图所示。

enter image description here

您可以检查设备支持的身份验证类型,包括Touch ID、FaceID或无。

编辑:

Apple已更新此枚举LABiometryType的值。现在none已过时

enter image description here

使用Swift 5检查支持的生物识别类型的扩展:

import LocalAuthentication

extension LAContext {
    enum BiometricType: String {
        case none
        case touchID
        case faceID
    }

    var biometricType: BiometricType {
        var error: NSError?

        guard self.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) else {
            return .none
        }

        if #available(iOS 11.0, *) {
            switch self.biometryType {
            case .none:
                return .none
            case .touchID:
                return .touchID
            case .faceID:
                return .faceID
            @unknown default:
                #warning("Handle new Biometric type") 
            }
        }
        
        return  self.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) ? .touchID : .none
    }
}

在刚发布的Xcode 9.2 beta中,配合iOS 11.2,LABiometryType枚举值已更改为faceIDtouchID - tfrank377
1
@tfrank377 谢谢你提醒我。我已经更新了答案。 - Surjeet Singh
我们能否仅通过模拟器来检测设备是否支持Face ID或Touch ID? - shaqir saiyed
是的,您可以使用模拟器进行测试。选择模拟器->硬件->触摸ID->案例 这将为基于模拟器的两种提供支持。 - Surjeet Singh
1
你没有回答问题。问题不是关于它是什么,而是如何做到? - swift2geek
显示剩余2条评论

16

因为我非常喜欢扩展功能,所以我会用不同的措辞回答这个问题,但本质是相同的。这是一个可以直接使用的扩展。

import LocalAuthentication

extension LAContext {
    enum BiometricType: String {
        case none
        case touchID
        case faceID
    }

    var biometricType: BiometricType {
        var error: NSError?

        guard self.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) else {
            // Capture these recoverable error thru Crashlytics
            return .none
        }

        if #available(iOS 11.0, *) {
            switch self.biometryType {
            case .none:
                return .none
            case .touchID:
                return .touchID
            case .faceID:
                return .faceID
            }
        } else {
            return  self.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) ? .touchID : .none
        }
    }
}

使用方法如下:

var currentType = LAContext().biometricType

7

Objective C :)

/** Only interesting devices are enumerated here. To change view constraints depending
 on screen height. Or the top notch for iPhone X
 */
typedef NS_ENUM(NSUInteger, BPDeviceType) {
    BPDeviceTypeUnknown,
    BPDeviceTypeiPhone4,
    BPDeviceTypeiPhone5,
    BPDeviceTypeiPhone6,
    BPDeviceTypeiPhone6Plus,
    BPDeviceTypeiPhone7,
    BPDeviceTypeiPhone7Plus,
    BPDeviceTypeiPhoneX,
    BPDeviceTypeiPad
};

+ (BPDeviceType)getDeviceType {
    double screenHeight = [[UIScreen mainScreen] bounds].size.height;
    if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPad)
    {
        return BPDeviceTypeiPad;

    } else if (UI_USER_INTERFACE_IDIOM()== UIUserInterfaceIdiomPhone)
    {
        if (@available(iOS 11, *)) {
            UIEdgeInsets insets = [UIApplication sharedApplication].delegate.window.safeAreaInsets;
            if (insets.top > 0) {
                return BPDeviceTypeiPhoneX;
            }
        }

        if(screenHeight == 480) {
            return BPDeviceTypeiPhone4;
        } else if (screenHeight == 568) {
            return BPDeviceTypeiPhone5;
        } else if (screenHeight == 667) {
            return BPDeviceTypeiPhone6;
        } else if (screenHeight == 736) {
            return BPDeviceTypeiPhone6Plus;
        }
    }
    return BPDeviceTypeUnknown;
}

+ (BOOL) isBiometricIDAvailable {
    if (![LAContext class]) return NO;

    LAContext *myContext = [[LAContext alloc] init];
    NSError *authError = nil;
    if (![myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
        NSLog(@"%@", [authError localizedDescription]);
        return NO;
    }
    return YES;
}

+ (BOOL) isTouchIDAvailable {
    if (![LAContext class]) return NO;

    LAContext *myContext = [[LAContext alloc] init];
    NSError *authError = nil;
    if (![myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
        NSLog(@"%@", [authError localizedDescription]);
        return NO;
        // if (authError.code == LAErrorTouchIDNotAvailable) {}
    }

    if (@available(iOS 11.0, *)) {
        if (myContext.biometryType == LABiometryTypeTouchID){
            return YES;
        } else {
            return NO;
        }
    } else {
        return YES;
    }
}

+ (BOOL) supportFaceID {
    return [BPDeviceInfo getDeviceType] == BPDeviceTypeiPhoneX;
}

+ (BOOL) isFaceIDAvailable {
    if (![LAContext class]) return NO;

    LAContext *myContext = [[LAContext alloc] init];
    NSError *authError = nil;
    if (![myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
        NSLog(@"%@", [authError localizedDescription]);
        return NO;
    }

    if (@available(iOS 11.0, *)) {
        if (myContext.biometryType == LABiometryTypeFaceID){
            return YES;
        } else {
            return NO;
        }
    } else {
        return NO;
    }
}

7

面部识别是从iOS 11开始提供的功能,而iPhone X默认搭载了iOS 11系统。在LocalAuth框架中,他们添加了一个“biometryType”属性,可以让你检测设备是否支持面部识别。

/// checks if face id is avaiable on device
func faceIDAvailable() -> Bool {
    if #available(iOS 11.0, *) {
        let context = LAContext()
        return (context.canEvaluatePolicy(LAPolicy.deviceOwnerAuthentication, error: nil) && context.biometryType == .faceID)
    }
    return false
}

我们能否仅使用模拟器来检测设备是否支持Face ID或Touch ID? - shaqir saiyed
@shaqirsaiyed 是的。我们可以检测设备是否支持Face ID或Touch ID。当您在iPhoneX或更高版本的设备上运行应用程序时,它会自动检测Face ID,否则对于iPhone 8或iPhone 8Plus设备,它将检测Touch ID。 - Usman Awan
如果我没有任何物理设备,而是在模拟器中运行,那么我能检测到吗? - shaqir saiyed

7

我为本地认证制作了一个单例类,因为它可以使用整个应用程序的static属性一次初始化一个实例。

import Foundation
import LocalAuthentication

public class LocalAuthManager: NSObject {

    public static let shared = LocalAuthManager()
    private let context = LAContext()
    private let reason = "Your Request Message"
    private var error: NSError?

    enum BiometricType: String {
        case none
        case touchID
        case faceID
    }

    private override init() {

    }

    // check type of local authentication device currently support
    var biometricType: BiometricType {
        guard self.context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) else {
            return .none
        }

        if #available(iOS 11.0, *) {
            switch context.biometryType {
            case .none:
                return .none
            case .touchID:
                return .touchID
            case .faceID:
                return .faceID
            }
        } else {
            return self.context.canEvaluatePolicy(.deviceOwnerAuthentication, error: nil) ? .touchID : .none
        }
    }
}

实施:

func checkAuth() {
     let authType = LocalAuthManager.shared.biometricType
        switch authType {
        case .none:
            print("Device not registered with TouchID/FaceID")
        case .touchID:
            print("Device support TouchID")
        case .faceID:
            print("Device support FaceID")
        }
 }

5
这里还有一种通过属性的方式(例如,使用您的访问实例)进行操作的方法。
import LocalAuthentication


enum BiometricType {
    case none
    case touchID
    case faceID
}

var biometricType: BiometricType {
    get {
        let context = LAContext()
        var error: NSError?

        guard context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) else {
            print(error?.localizedDescription ?? "")
            return .none
        }

        if #available(iOS 11.0, *) {
            switch context.biometryType {
            case .none:
                return .none
            case .typeTouchID:
                return .touchID
            case .typeFaceID:
                return .faceID
            }
        } else {
            return  .touchID
        }
    }
}

我们能否只使用模拟器来检测设备是否支持Face ID或Touch ID? - shaqir saiyed

5

这是我的“帮助类”,它包括了验证码

enum BiometryType: String {
    case none = "None"
    case faceID = "Face ID"
    case touchID = "Touch ID"
    case passcode = "Passcode"
}


var biometryType: BiometryType {
    let myContext = LAContext()

    let hasAuthenticationBiometrics = myContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil)
    let hasAuthentication = myContext.canEvaluatePolicy(.deviceOwnerAuthentication, error: nil)

    if #available(iOS 11.0, *) {
        if hasAuthentication {
            if hasAuthenticationBiometrics {
                switch myContext.biometryType {
                case .none: return .none
                case .faceID: return .faceID
                case .touchID: return .touchID
                }
            } else {
                return .passcode
            }
        } else {
            return .none
        }
    } else {
        if hasAuthentication {
            if hasAuthenticationBiometrics {
                return .touchID
            } else {
                return .passcode
            }
        } else {
            return .none
        }
    }
}

3

你需要向case中添加@unknown!!!

在较新的版本(Xcode 13...)中,你可能需要指定"unknown"

#warning("处理新生物识别类型") 不会返回值

import LocalAuthentication

class BiometricType{


static func biometricType() -> BiometricType {
    let authContext = LAContext()
    if #available(iOS 11, *) {
        let _ = authContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil)
        switch(authContext.biometryType) {
        case .none:
            return .none
        case .touchID:
            return .touch
        case .faceID:
            return .face
        @unknown default:
            return .unknown
        }
    } else {
        return authContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) ? .touch : .none
    }
}

enum BiometricType {
    case none
    case touch
    case face
    case unknown
}

}

3
-(BOOL)faceIDAvailable {
        LAContext *myContext = [[LAContext alloc] init];
        NSError *authError = nil;

        if (@available(iOS 11.0, *)) {
            if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&authError] && myContext.biometryType == LABiometryTypeFaceID) {
                return true;
            }
        }
      return false;

}
-(BOOL)touchIDAvailable {
        LAContext *myContext = [[LAContext alloc] init];
        NSError *authError = nil;

        if (@available(iOS 11.0, *)) {
            if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&authError] && myContext.biometryType == LABiometryTypeTouchID) {
                return true;
            }
        }
      return false;

}

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