Определите, поддерживает ли iOS устройство TouchID без установки пароля

В настоящее время я разрабатываю приложение для iOS, которое позволяет пользователям входить в приложение с помощью TouchID, но сначала они должны сначала установить пароль внутри приложения. Проблема в том, чтобы показать опцию пароля настройки для включения входа в систему TouchID, мне нужно определить, поддерживает ли устройство iOS TouchID.

Используя LAContext и canEvaluatePolicy (см. Ответы здесь, если устройство поддерживает Touch ID), я могу определить, поддерживает ли текущее устройство TouchID, если пользователь установил код доступа на своем устройстве iOS. Вот мой фрагмент кода (я использую Xamarin, поэтому он в С#):

static bool DeviceSupportsTouchID () 
{
    if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
    {
        var context = new LAContext();
        NSError authError;
        bool touchIDSetOnDevice = context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out authError);

        return (touchIDSetOnDevice || (LAStatus) Convert.ToInt16(authError.Code) != LAStatus.TouchIDNotAvailable);
    }

    return false;
}

Если пользователь не установил пароль устройства, authError просто выдаст ошибку " PasscodeNotSet " независимо от того, поддерживает ли устройство TouchID или нет.

Если пользовательское устройство поддерживает TouchID, я хочу всегда показывать опцию TouchID в своем приложении независимо от того, установил ли пользователь пароль на своем устройстве (я просто предупрежу пользователя, чтобы он сначала установил пароль на своем устройстве). И наоборот, если пользовательское устройство не поддерживает TouchID, я, очевидно, не хочу показывать опцию TouchID в моем приложении.

Итак, мой вопрос: есть ли хороший способ последовательно определить, поддерживает ли устройство iOS TouchID, независимо от того, установил ли пользователь пароль на своем устройстве?

Единственный обходной путь, о котором я могу подумать, - это определить архитектуру устройства (на который дан ответ в разделе "Определить, является ли устройство iOS 32- или 64-разрядным)", поскольку TouchID поддерживается только на устройствах с 64-разрядной архитектурой. Тем не менее, я смотрю, есть ли лучший способ сделать это.

Ответы

Ответ 1

В заключение обсуждения ниже, в настоящее время невозможно определить, действительно ли устройство поддерживает TouchID или нет, когда пользователь не установил код доступа на своем устройстве.

Я сообщил об этой уязвимости TouchID на Apple, репортер ошибок. Те, кто хочет следить за проблемой, могут увидеть ее на Open Radar здесь: http://www.openradar.me/20342024

Спасибо @rckoenes за вклад :)

РЕДАКТИРОВАТЬ

Оказывается, кто-то уже сообщал о подобной проблеме (# 18364575). Вот ответ Apple относительно проблемы:

"Инжиниринг установил, что эта проблема ведет себя как задумано, основываясь на следующей информации:

Если пароль не установлен, вы не сможете обнаружить присутствие Touch ID. Когда пароль установлен, canEvaluatePolicy в конечном итоге вернет LAErrorTouchIDNotAvailable или LAErrorTouchIdNotEnrolled, и вы сможете обнаружить наличие/состояние Touch ID.

Если пользователи отключили пароль на телефоне с помощью Touch ID, они знали, что не смогут использовать Touch ID, поэтому приложениям не нужно обнаруживать присутствие Touch ID или продвигать функции на основе Touch ID. "

Итак... окончательный ответ от Apple - нет. :(

Примечание: похожий вопрос от StackOverflow от человека, который сообщил об этом → проверка iOS8, если у устройства есть Touch ID (интересно, почему я не нашел этот вопрос раньше, несмотря на мой обширный поиск...)

Ответ 2

Правильный способ обнаружения TouchID доступен:

BOOL hasTouchID = NO;
// if the LAContext class is available
if ([LAContext class]) {
    LAContext *context = [LAContext new];
    NSError *error = nil;
    hasTouchId = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
}

Извините, что он находится в Objective-C, вам, возможно, придется перевести его на С#.

Вам следует воздержаться от проверки версии системы и просто проверить, доступен ли класс или методы.

Ответ 3

Я знаю, что это вопрос прошлого года, но это решение не делает то, что вам нужно? (Код Swift)

if #available(iOS 8.0, *) {
    var error: NSError?
    let hasTouchID = LAContext().canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error)

    //Show the touch id option if the device has touch id hardware feature (even if the passcode is not set or touch id is not enrolled)
    if(hasTouchID || (error?.code != LAError.TouchIDNotAvailable.rawValue)) {
        touchIDContentView.hidden = false
    } 
}

Затем, когда пользователь нажимает кнопку для входа с сенсорным идентификатором:

@IBAction func loginWithTouchId() {
    let context = LAContext()

    var error: NSError?
    let reasonString = "Log in with Touch ID"

    if (context.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error)) {
        [context.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: reasonString, reply: { (success: Bool, evalPolicyError: NSError?) -> Void in
            //Has touch id. Treat the success boolean
        })]
    } else { 
        //Then, if the user has touch id but is not enrolled or the passcode is not set, show a alert message
        switch error!.code{

        case LAError.TouchIDNotEnrolled.rawValue:
            //Show alert message to inform that touch id is not enrolled
            break

        case LAError.PasscodeNotSet.rawValue:
            //Show alert message to inform that passcode is not set
            break

        default:
            // The LAError.TouchIDNotAvailable case.
            // Will not catch here, because if not available, the option will not visible
        }
    }
}

Надеюсь, поможет!

Ответ 4

Для цели C
Он отлично работает на всех устройствах без проверки версии устройства.

- (void)canAuthenticatedByTouchID{
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = touchIDRequestReason;

if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
 }else{
    switch (authError.code) {
        case kLAErrorTouchIDNotAvailable:
            [labelNotSupportTouchID setHidden:NO];
            [switchBtn setHidden:YES];
            [labelEnableTouchid setHidden:YES];
            static dispatch_once_t onceToken;
            dispatch_once(&onceToken, ^{
                [self showAlertMessage:@"EyeCheck Pro" message:@"Device does not support Touch ID Service."];
            });

            break;
    }
  }
}

Ответ 5

Вот немного утомительный способ выяснить, имеет ли устройство физический сенсор сенсорного датчика.

+ (BOOL)isTouchIDExist {
if(![LAContext class]) //Since this mandotory class is not there, that means there is no physical touch id.
    return false;

//Get the current device model name
size_t size;
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
char *model = malloc(size);
sysctlbyname("hw.machine", model, &size, NULL, 0);
NSString *deviceModel = [NSString stringWithCString:model encoding:NSUTF8StringEncoding];

//Devices that does not support touch id
NSArray *deviceModelsWithoutTouchID = [[NSArray alloc]
                                       initWithObjects:
                                       @"iPhone1,1", //iPhone
                                       @"iPhone1,2", //iPhone 3G
                                       @"iPhone2,1", //iPhone 3GS
                                       @"iPhone3,1", //iPhone 4
                                       @"iPhone3,2",
                                       @"iPhone3,3",
                                       @"iPhone4,1", //iPhone 4S
                                       @"iPhone5,1", //iPhone 5
                                       @"iPhone5,2",
                                       @"iPhone5,3", //iPhone 5C
                                       @"iPhone5,4",
                                       @"iPod1,1", //iPod
                                       @"iPod2,1",
                                       @"iPod3,1",
                                       @"iPod4,1",
                                       @"iPod5,1",
                                       @"iPod7,1",
                                       @"iPad1,1", //iPad
                                       @"iPad2,1", //iPad 2
                                       @"iPad2,2",
                                       @"iPad2,3",
                                       @"iPad2,4",// iPad mini 1G
                                       @"iPad2,5",
                                       @"iPad2,5",
                                       @"iPad2,7",
                                       @"iPad3,1", //iPad 3
                                       @"iPad3,2",
                                       @"iPad3,3",
                                       @"iPad3,4", //iPad 4
                                       @"iPad3,5",
                                       @"iPad3,6",
                                       @"iPad4,1", //iPad Air
                                       @"iPad4,2",
                                       @"iPad4,3",
                                       @"iPad4,4", //iPad mini 2
                                       @"iPad4,5",
                                       @"iPad4,6",
                                       @"iPad4,7",
                                       nil];

return ![deviceModelsWithoutTouchID containsObject:deviceModel];

}

Ссылка: https://www.theiphonewiki.com/wiki/Models https://en.wikipedia.org/wiki/IOS

Ответ 6

Ниже описан способ определения того, поддерживается ли на устройстве Touch Id или Face ID.

open class LocalAuth: NSObject {

    public static let shared = LocalAuth()

    private override init() {}

    var laContext = LAContext()

    func canAuthenticate() -> Bool {
        var error: NSError?
        let hasTouchId = laContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)
        return hasTouchId
    }

    func hasTouchId() -> Bool {
        if canAuthenticate() && laContext.biometryType == .touchID {
            return true
        }
        return false
    }

    func hasFaceId() -> Bool {
        if canAuthenticate() && laContext.biometryType == .faceID {
            return true
        }
        return false
    }

}

И следующее - Использование вышеуказанного общего кода.

if LocalAuth.shared.hasTouchId() {
    print("Has Touch Id")
} else if LocalAuth.shared.hasFaceId() {
    print("Has Face Id")
} else {
    print("Device does not have Biometric Authentication Method")
}

Ответ 7

Для iOS 11+ вы можете использовать biometryType: LABiometryType of LAContext. Больше из документации Apple:

/// Indicates the type of the biometry supported by the device.
///
/// @discussion  This property is set only when canEvaluatePolicy succeeds for a biometric policy.
///              The default value is LABiometryTypeNone.
@available(iOS 11.0, *)
open var biometryType: LABiometryType { get }

@available(iOS 11.0, *)
public enum LABiometryType : Int {

    /// The device does not support biometry.
    @available(iOS 11.2, *)
    case none

    /// The device does not support biometry.
    @available(iOS, introduced: 11.0, deprecated: 11.2, renamed: "LABiometryType.none")
    public static var LABiometryNone: LABiometryType { get }

    /// The device supports Touch ID.
    case touchID

    /// The device supports Face ID.
    case faceID
}