簡體   English   中英

如何以編程方式檢查“Face Id”和“Touch Id”的支持

[英]How to programmatically check support of 'Face Id' and 'Touch Id'

我為我的應用程序安全目的集成了LocalAuthentication ,它一直支持基於“Touch Id”的支持。 但是現在,蘋果最近還添加了基於“Face Id”的身份驗證。

如何檢查設備支持哪種類型的身份驗證。 觸控 ID 還是面容 ID?

我一直在努力讓它工作,發現我需要使用 LAContext 的單個實例,並且需要在獲取biometryType 之前調用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
}

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

LABiometryType是一個枚舉,其值如附加圖像中所示

在此處輸入圖片說明

您可以在 Touch ID 和 FaceID 之間檢查設備支持哪種身份驗證類型或不支持。

編輯:

Apple 已更新此枚舉LABiometryType 的值。 現在沒有被棄用

在此處輸入圖片說明

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

因為我是擴展的忠實粉絲。 我對這個答案的表述略有不同。 本質是一樣的。 這是一個插入式擴展。

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

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

面容 ID可從 iOS 11 使用,iPhone X 默認隨 iOS 11 一起提供。 在 LocalAuth 框架中,他們添加了一個“biometryType”屬性,可以讓您檢測設備上是否可以使用 Face ID。

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

}

此代碼在 Xcode 9.2 - 9.4上構建時沒有警告(請參閱9.1注釋):

@objc let biometricsAuthPolicy = LAPolicy.deviceOwnerAuthenticationWithBiometrics

@objc func supportsFaceID() -> Bool {
    if #available(iOS 11.0, *) {
        return biometryType() == .faceID // return biometryType() == .typeFaceID for Xcode 9.1
    }
    return false
}

@objc func supportsTouchID() -> Bool {
    if #available(iOS 11.0, *) {
        return biometryType() == .touchID // return biometryType() == .typeTouchID for Xcode 9.1
    }

    let context = LAContext()
    return context.canEvaluatePolicy(biometricsAuthPolicy, error: nil)
}

@objc @available(iOS 11.0, *)
func biometryType() -> LABiometryType {
    var error: NSError?
    let context = LAContext()

    guard context.canEvaluatePolicy(biometricsAuthPolicy, error: &error) else {
        if #available(iOS 11.2, *) {
            return .none
        }
        return LABiometryType.LABiometryNone // return LABiometryType.none for Xcode 9.1
    }

    return context.biometryType
}

來自@Markicevic 擴展,但忽略用戶未注冊的情況等...

extension LAContext {

enum BiometricType: String {
    case none = ""
    case touchID = "Touch ID"
    case faceID = "Face ID"
}

static var biometricType: BiometricType {
    var error: NSError?

    let context = LAContext()

    _ = context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)

    if error?.code == LAError.Code.touchIDNotAvailable.rawValue {
        return .none
    }

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

}

swift 5 的更新,切換流程需要一個默認條件。

import Foundation
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 through fabric
            return .none
        }

        if #available(iOS 11.0, *) {
            switch self.biometryType {
            case .touchID:
                return .touchID
            case .faceID:
                return .faceID
            default:
                return .none
            }
        }

        return self.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) ? .touchID : .none
    }

}

測試用例在下面

// need to import LocalAuthentication in the calling file
// import LocalAuthentication
let currentType = LAContext().biometricType
print("biometry type > \(currentType)")
// biometry type > touchID

如果你想在模擬器中測試,你需要注冊touchId/faceId。
模擬器 > 硬件 > Touch ID/Face ID > 已注冊。 在此處輸入圖片說明

請參考“使用面容 ID 或觸控 ID用戶登錄到您的應用”中提供的蘋果示例代碼,這將有助於輕松理解身份驗證。

Apple 示例代碼鏈接 - https://docs-assets.developer.apple.com/published/fbfd13f4d9/LoggingAUserIntoYourAppWithFaceIDOrTouchID.zip

閱讀以下鏈接中示例代碼的詳細說明。 https://developer.apple.com/documentation/localauthentication/logging_a_user_into_your_app_with_face_id_or_touch_id

開始在 12 Pro 上測試一些新應用,發現我發布的應用只有 Touch ID 而沒有 Face ID。

我來到這里並看到了所有這些,所以我開始嘗試更改我的 Touch ID 代碼,但我需要做的就是將隱私密鑰添加到 info.plist。

信息屬性列表➕

然后向下滾動到:Privacy- Face ID Usage Description, (Type: String), (Value: YES)

太簡單了😀

您需要將@unknown 添加到案例中!!!

在較新的版本(Xcode 13 ...)中,您可能必須指定“未知”

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

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM