IOS8 проверяет, имеет ли устройство Touch ID
LAContext имеет способ проверить, может ли устройство оценивать идентификатор касания и выдавать сообщение об ошибке.
Проблема в том, что то же сообщение об ошибке "LAErrorPasscodeNotSet" задается системой в двух случаях:
1) Если пользователь имеет идентификатор Touch, но отключил его в настройках (iPhone 5 с iOS8)
2) Если у устройства нет сенсорного ID (iPad с iOS8)
В: Как проверить, поддерживает ли устройство Touch ID, но не включил его в настройках?
Update:
Создал билет в Apple по поводу этой ошибки (ID # 18364575) и получил ответ:
"Инженерия определила, что эта проблема ведет себя как предполагалось на основе следующей информации:
Если код доступа не установлен, вы не сможете обнаружить присутствие сенсорного идентификатора. Как только код доступа установлен, canEvaluatePolicy в конечном итоге вернет LAErrorTouchIDNotAvailable или LAErrorTouchIdNotEnrolled, и вы сможете обнаружить присутствие/состояние Touch ID.
Если пользователи отключили код доступа на телефоне с Touch ID, они знали, что они не смогут использовать Touch ID, поэтому приложениям не нужно обнаруживать присутствие Touch ID или продвигать функции Touch ID. "
Ответы
Ответ 1
Возможно, вы можете написать свой собственный метод, чтобы проверить, на каком устройстве вы работаете, потому что если возвращенная ошибка будет такой же, было бы трудно точно определить, поддерживает ли Touch ID. Я бы пошел с чем-то вроде этого:
int sysctlbyname(const char *, void *, size_t *, void *, size_t);
- (NSString *)getSysInfoByName:(char *)typeSpecifier
{
size_t size;
sysctlbyname(typeSpecifier, NULL, &size, NULL, 0);
char *answer = malloc(size);
sysctlbyname(typeSpecifier, answer, &size, NULL, 0);
NSString *results = [NSString stringWithCString:answer encoding: NSUTF8StringEncoding];
free(answer);
return results;
}
- (NSString *)modelIdentifier
{
return [self getSysInfoByName:"hw.machine"];
}
После определения идентификатора модели я бы просто проверить, равен ли идентификатор модели, одна из моделей, поддерживающих Touch ID:
- (BOOL)hasTouchID
{
NSArray *touchIDModels = @[ @"iPhone6,1", @"iPhone6,2", @"iPhone7,1", @"iPhone7,2", @"iPad5,3", @"iPad5,4", @"iPad4,7", @"iPad4,8", @"iPad4,9" ];
NSString *model = [self modelIdentifier];
return [touchIDModels containsObject:model];
}
В массиве содержится все идентификаторы модели, поддерживающие Touch ID, которые:
- iPhone 5s
- iPhone 6
- iPhone 6 +
- iPad Air 2
- iPad Mini 3
Единственным недостатком этого метода является то, что после того, как новые устройства будут выпущены с Touch ID, массив модели необходимо будет обновить вручную.
Ответ 2
Интеграция сенсорного ID
Теперь мы переходим к основной части учебного пособия... интеграции Touch ID с приложением. Как оказалось, Apple выпустила довольно стандартный код для доступа к Touch ID. Код исходит из локальной проверки подлинности и выглядит следующим образом:
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = @"Used for quick and secure access to the test app";
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
if (success) {
// User authenticated successfully, take appropriate action
}
else {
// User did not authenticate successfully, look at error and take appropriate action
}
}];
}
else {
// Could not evaluate policy; look at authError and present an appropriate message to user }
Давайте посмотрим на каждую строку, чтобы увидеть, что она делает:
Строка 1: Здесь мы создаем объект LAContext. Класс LAContext отвечает за обработку контекста для аутентификации. Проще говоря, мы используем объект LAContext, чтобы проверить, доступен ли тип аутентификации. В этом уроке мы позже проверим, есть ли опция "if" touch ID.
Строка 2: Нам нужен NSError, чтобы LAContext мог использовать его для возврата, если есть ошибка.
Строка 3: мы устанавливаем NSString с описанием, которое оно помещает на экран, чтобы пользователь знал, почему на экране появился вид сенсорного идентификатора.
Строка 5: Здесь мы используем константу LAContext, вызывая метод canEvaluatePolicy: и отправляя ей константу LAPolicy в качестве аргумента. В этом случае мы передаем LAPolicyDeviceOwnerAuthenticationWithBiometrics. Если это не удается, либо сенсорный идентификатор не настроен на совместимом устройстве, либо сенсорный идентификатор недоступен на устройстве... подумайте, что iPhone 4S, 5 или 5c запускает приложение. Кроме того, это не учитывает устройство, работающее под управлением iOS 7, поэтому, если вы планируете проверять подлинность отпечатка пальца в приложении, убедитесь, что вы проверяете, что работаете с совместимым устройством, а если нет, добавьте другие параметры, такие как пароль на пин-код для доступа к приложению.
Линии 6, 7 и 8: Если пользователь может выполнить аутентификацию с помощью биометрии, мы теперь можем вызвать метод valuPolicy для нашего объекта LAContext. Мы делаем это, передавая одну и ту же константу, LAPolicyDeviceOwnerAuthenticationWithBiometrics, а также передаем нашу строку причин и затем определяем блок для ответа, который будет обрабатываться.
В результате мы получим ДА или НЕТ. Если ДА, то строка 10 - это место, где мы помещаем код для положительного ответа. Аналогично, строка 12 - это то, где мы помещаем наш код отказа.
Наконец, в строке 15 мы имеем инструкцию ELSE, которая выполняется, если строка 5 не проходит тест... т.е. биометрические данные недоступны. Мы можем проверить указатель authError, чтобы получить причину и представить ее пользователю, если это необходимо.
Наконец, чтобы это не отображало ошибок, нам нужно импортировать локальную систему проверки подлинности в наш проект:
Итак, добавим этот код в наш проект. Откройте ViewController.m и вверху, импортируйте локальную структуру проверки подлинности.
Подробнее см. по ссылке: http://www.devfright.com/touch-id-tutorial-objective-c/
Ответ 3
В Swift 3
fileprivate func deviceSupportsTouchId(success: @escaping () -> (), failure: @escaping (NSError) -> ()) {
let context = LAContext()
var authError: NSError?
let touchIdSetOnDevice = context.canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: &authError)
if touchIdSetOnDevice {
DispatchQueue.main.async {
success()
}
}
else {
DispatchQueue.main.async {
failure(error!)
}
}
}
deviceSupportsTouchId() return Успех, если устройство имеет сенсорный идентификатор.
Если нет, функция вернет ошибку, предоставив вам следующий код ошибки, если touchIDNotEnrolled еще не установлен.
LAError.Code.touchIDNotEnrolled.rawValue
Вы можете обрабатывать его, используя это значение.
Ответ 4
Здесь вы можете проверить, Touch-ID и Face-ID оба (с iOS 11 +)
Используйте свойство biometryType
of LAContext
для проверки и оценки доступной биометрической политики. (Для аутентификации паролей при биометрическом сбое используйте: LAPolicyDeviceOwnerAuthentication
)
Попробуйте это и посмотрите:
Objective-C:
LAContext *laContext = [[LAContext alloc] init];
NSError *error;
// For a passcode authentication , when biometric fails, use: LAPolicyDeviceOwnerAuthentication
//if ([laContext canEvaluatePolicy: LAPolicyDeviceOwnerAuthentication error:&error]) {
if ([laContext canEvaluatePolicy: LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
if (error != NULL) {
// handle error
} else {
if (@available(iOS 11, *)) {
if (laContext.biometryType == LABiometryTypeFaceID) {
//localizedReason = "Unlock using Face ID"
NSLog(@"FaceId support");
} else if (laContext.biometryType == LABiometryTypeTouchID) {
//localizedReason = "Unlock using Touch ID"
NSLog(@"TouchId support");
} else {
//localizedReason = "Unlock using Application Passcode"
NSLog(@"No biometric support or Denied biometric support");
}
} else {
// Fallback on earlier versions
}
[laContext evaluatePolicy: LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:@"Test Reason" reply:^(BOOL success, NSError * _Nullable error) {
if (error != NULL) {
// handle error
} else if (success) {
// handle success response
} else {
// handle false response
}
}];
}
}
Swift:
let laContext = LAContext()
var error: NSError?
let biometricsPolicy = LAPolicy.deviceOwnerAuthentication //LAPolicy.deviceOwnerAuthenticationWithBiometrics
if laContext.isCredentialSet(LACredentialType.applicationPassword) {
print("Passsword is set")
}
let localizedFallbackTitle = "Unlock Using Device Passcode"
let localizedCancelTitle = "Use Application Passcode"
if (laContext.canEvaluatePolicy(biometricsPolicy, error: &error)) {
if let laError = error {
print("laError - \(laError)")
return
}
//print("biometricsPolicy - \(biometricsPolicy.rawValue)")
UINavigationBar.appearance().tintColor = UIColor.red
var localizedReason = "My Reason to be displayed on face id prompt"
if #available(iOS 11.0, *) {
if (laContext.biometryType == LABiometryType.faceID) {
//localizedReason = "Unlock using Face ID"
print("FaceId support")
} else if (laContext.biometryType == LABiometryType.touchID) {
//localizedReason = "Unlock using Touch ID"
print("TouchId support")
} else {
//localizedReason = "Unlock using Application Passcode"
print("No Biometric support")
}
} else {
// Fallback on earlier versions
}
laContext.localizedFallbackTitle = localizedFallbackTitle
laContext.localizedCancelTitle = localizedCancelTitle
//laContext.localizedReason = "test loc reason"
laContext.evaluatePolicy(biometricsPolicy, localizedReason: localizedReason, reply: { (isSuccess, error) in
DispatchQueue.main.async(execute: {
if let laError = error {
print("laError - \(laError)")
} else {
if isSuccess {
print("sucess")
} else {
print("failure")
}
}
})
})
}