J'ai intégré LocalAuthentication pour les besoins de la sécurité de mon application, qui prenait en charge le support basé sur 'Touch Id'. Mais à présent, Apple a récemment ajouté une authentification basée sur 'Face Id'.
Comment puis-je vérifier le type d'authentification pris en charge par un périphérique? Touchez Id ou visage Id?
Avec Xcode 9, regardez LocalAuthentication -> LAContext -> LABiometryType .
LABiometryType est une énumération avec des valeurs identiques à celles de l'image jointe.
Vous pouvez vérifier le type d'authentification pris en charge par le périphérique entre Touch ID et FaceID ou aucun.
Modifier:
Apple a mis à jour les valeurs pour cette énumération LABiometryType. none est obsolète maintenant.
J'ai eu du mal à faire en sorte que cela fonctionne et j'ai constaté que je devais utiliser une seule instance de LAContext et que je devais appeler LAContextInstance .canalevatePolicy (.deviceOwnerAuthenticationWithBiometrics, error: nil) avant d'obtenir le biometryType. Voici mon code final prenant en charge les anciennes versions iOS:
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
}
Objectif 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;
}
}
Comme je suis un grand fan de l'extension. Je formule cette réponse un peu différemment. Essense est le même. Ceci est une extension sans rendez-vous.
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
}
}
}
Utilisez comme ceci:
var currentType = LAContext().biometricType
Voici un moyen supplémentaire via la propriété (par exemple, sur votre instance d'accès).
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
}
}
}
L'identité du visage est disponible à partir d'iOS 11 et l'iPhone X est livré avec iOS 11 par défaut. Dans le cadre LocalAuth, ils ont ajouté une propriété 'biometryType' qui peut vous permettre de détecter si un ID de visage est disponible sur le périphérique.
/// 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
}
Voici ma "classe d'assistance", elle inclut également le code d'accès
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
}
}
}
De l'extension @Markicevic, mais en ignorant les cas où l'utilisateur n'est pas inscrit, etc.
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
}
}
}
Ce code est construit sans avertissements sur Xcode 9.2
-9.4
(voir les commentaires pour 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
}