我已经为我的应用程序安全目的集成了LocalAuthentication,它支持基于'Touch Id'的支持。但现在,苹果最近还添加了基于'Face Id'的身份验证方式。
我该如何检查设备支持哪种类型的身份验证方式。Touch Id还是Face Id?
我已经为我的应用程序安全目的集成了LocalAuthentication,它支持基于'Touch Id'的支持。但现在,苹果最近还添加了基于'Face Id'的身份验证方式。
我该如何检查设备支持哪种类型的身份验证方式。Touch Id还是Face Id?
我一直在努力让这个工作,发现我需要使用单个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
}
biometryType
的文档说明:仅当生物识别策略的canEvaluatePolicy
成功时,才设置此属性。因此,如果canEvaluatePolicy
失败(例如touchid/faceid完全未激活或按应用程序禁用),则biometricType()
返回.none
。因此,biometricType()
的检查不是硬件是否可用,而是应用程序是否可以访问硬件。 - Valeriy Van使用Xcode 9,请查看LocalAuthentication->LAContext->LABiometryType。
LABiometryType是一个枚举类型,其值如附图所示。
您可以检查设备支持的身份验证类型,包括Touch ID、FaceID或无。
编辑:
Apple已更新此枚举LABiometryType的值。现在none已过时。
使用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
}
}
LABiometryType
枚举值已更改为faceID
和touchID
。 - tfrank377因为我非常喜欢扩展功能,所以我会用不同的措辞回答这个问题,但本质是相同的。这是一个可以直接使用的扩展。
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
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;
}
}
面部识别是从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
}
我为本地认证制作了一个单例类,因为它可以使用整个应用程序的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")
}
}
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
}
}
}
这是我的“帮助类”,它包括了验证码
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
}
}
}
在较新的版本(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
}
}
-(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;
}