[英]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)
太簡單了😀
在較新的版本(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.