wake-up-neo.com

touchIDLockout in iOS 11.0 veraltet

Beim Kompilieren meiner Anwendung mit Xcode 9 für IOS11 werden folgende Warnungen angezeigt:

warning: 'touchIDLockout' was deprecated in iOS 11.0: use LAErrorBiometryLockout

warning: 'touchIDNotEnrolled' was deprecated in iOS 11.0: use LAErrorBiometryNotEnrolled

warning: 'touchIDNotAvailable' was deprecated in iOS 11.0: use LAErrorBiometryNotAvailable

Ich verwende touchID, aber ich benutze kein touchIdLockout ... cste und die touchID funktioniert einwandfrei.

Wie kann ich diese Warnungen entfernen?


Bearbeiten (nicht vom ursprünglichen Autor):

Ich habe das auf eine einzige Ursache zurückgeführt. Es genügt, in meinem Code LAError aus dem LocalAuthentication-Framework zu referenzieren, damit diese Warnungen angezeigt werden.

Schritte zum Reproduzieren (versucht in Xcode 9.2):

  1. Erstellen Sie eine neue iOS-App (Vorlage für Einzelansicht). Beachten Sie, dass das iOS-Bereitstellungsziel auf iOS 11.2 eingestellt ist.
  2. Fügen Sie diese Zeilen zu AppDelegate.Swift hinzu:

    import LocalAuthentication
    

    Und eine einzelne Zeile in appDidFinishLaunching:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        let _: LAError? = nil
        return true
    }
    
  3. App erstellen.

Die let _: LAError? = nil-Zeile reicht aus, um die drei Warnungen anzuzeigen. Die Warnungen sind jedoch keiner bestimmten Codezeile zugeordnet. Sie werden im Erstellungsprotokoll ohne Datei-/Zeilenreferenz angezeigt:

<unknown>:0: warning: 'touchIDLockout' was deprecated in iOS 11.0: use LAErrorBiometryLockout
<unknown>:0: warning: 'touchIDNotEnrolled' was deprecated in iOS 11.0: use LAErrorBiometryNotEnrolled
<unknown>:0: warning: 'touchIDNotAvailable' was deprecated in iOS 11.0: use LAErrorBiometryNotAvailable

Hier ist ein Screenshot:Screenshot der Warnungen in Xcode

Und ein Beispielprojekt:Beispielprojekt zum Download (Xcode 9.2)

Als Referenz habe ich dies Apple mitgeteilt. Radar # 36028653.

19
sebastien

Kurze Antwort: Es sieht für mich wie ein Compiler-Fehler aus, verursacht durch den Import einer C-Enumeration, die mehrere Konstanten Mit demselben Wert definiert.

Lange Antwort: Leider habe ich keine Lösung, wie ich die Abwertung der Warnung vermeiden kann, nur eine mögliche Erklärung, was sie verursacht. 

Die LAError-Codes sind als C-Aufzählung in <LAError.h> im LocalAuthentication-Framework definiert. Hier ist ein Auszug aus dieser Definition:

// Error codes
#define kLAErrorAuthenticationFailed                       -1
#define kLAErrorUserCancel                                 -2
// ...
#define kLAErrorTouchIDNotAvailable                        -6
#define kLAErrorTouchIDNotEnrolled                         -7
#define kLAErrorTouchIDLockout                             -8
// ...
#define kLAErrorBiometryNotAvailable                        kLAErrorTouchIDNotAvailable
#define kLAErrorBiometryNotEnrolled                         kLAErrorTouchIDNotEnrolled
#define kLAErrorBiometryLockout                             kLAErrorTouchIDLockout

typedef NS_ENUM(NSInteger, LAError)
{
    LAErrorAuthenticationFailed = kLAErrorAuthenticationFailed,
    LAErrorUserCancel = kLAErrorUserCancel,
    // ...
    LAErrorTouchIDNotAvailable NS_ENUM_DEPRECATED(10_10, 10_13, 8_0, 11_0, "use LAErrorBiometryNotAvailable") = kLAErrorTouchIDNotAvailable,
    LAErrorTouchIDNotEnrolled NS_ENUM_DEPRECATED(10_10, 10_13, 8_0, 11_0, "use LAErrorBiometryNotEnrolled") = kLAErrorTouchIDNotEnrolled,
    LAErrorTouchIDLockout NS_ENUM_DEPRECATED(10_11, 10_13, 9_0, 11_0, "use LAErrorBiometryLockout")
    __WATCHOS_DEPRECATED(3.0, 4.0, "use LAErrorBiometryLockout") __TVOS_DEPRECATED(10.0, 11.0, "use LAErrorBiometryLockout") = kLAErrorTouchIDLockout,
    // ...
    LAErrorBiometryNotAvailable NS_ENUM_AVAILABLE(10_13, 11_0) __WATCHOS_AVAILABLE(4.0) __TVOS_AVAILABLE(11.0) = kLAErrorBiometryNotAvailable,
    LAErrorBiometryNotEnrolled NS_ENUM_AVAILABLE(10_13, 11_0) __WATCHOS_AVAILABLE(4.0) __TVOS_AVAILABLE(11.0) = kLAErrorBiometryNotEnrolled,
    LAErrorBiometryLockout NS_ENUM_AVAILABLE(10_13, 11_0) __WATCHOS_AVAILABLE(4.0) __TVOS_AVAILABLE(11.0) = kLAErrorBiometryLockout,
    // ...
} NS_ENUM_AVAILABLE(10_10, 8_0) __WATCHOS_AVAILABLE(3.0) __TVOS_AVAILABLE(10.0);

Man kann sehen, dass "alte" (veraltete) und die "neuen" Fehlercodes Dieselben Werte verwenden. Beispielsweise sind sowohl LAErrorTouchIDNotAvailable als auch LAErrorBiometryNotAvailable als -6 definiert.

Das ist in C durchaus gültig, aber die Rohwerte einer Swift enum müssen sich gegenseitig unterscheiden. Anscheinend löst der Swift-Importer dies, indem er die neuen/duplizierten Fälle mit statischen Variablen abbildet.

Hier ist ein Auszug aus dem Swift-Mapping:

public struct LAError {

    public init(_nsError: NSError)
    public static var _nsErrorDomain: String { get }


    public enum Code : Int {
        case authenticationFailed
        case userCancel
        // ...
        @available(iOS, introduced: 8.0, deprecated: 11.0, message: "use LAErrorBiometryNotAvailable")
        case touchIDNotAvailable
        @available(iOS, introduced: 8.0, deprecated: 11.0, message: "use LAErrorBiometryNotEnrolled")
        case touchIDNotEnrolled
        @available(iOS, introduced: 9.0, deprecated: 11.0, message: "use LAErrorBiometryLockout")
        case touchIDLockout
        // ...
        @available(iOS 11.0, *)
        public static var biometryNotAvailable: LAError.Code { get }
        @available(iOS 11.0, *)
        public static var biometryNotEnrolled: LAError.Code { get }
        @available(iOS 11.0, *)
        public static var biometryLockout: LAError.Code { get }
        // ...
    }

    // ...
}

Und dies scheint die Ursache für die Abwertungswarnungen zu sein, und .__ auch für das in der Swift-Benutzer-Mailingliste angegebene Problem

dass es nicht möglich ist, eine erschöpfende und warnungsfreie switch-Anweisung für LAError zu schreiben.


Um meine Vermutung zu beweisen, habe ich das Problem mit einer benutzerdefinierten Enumeration reproduziert: Fügen Sie der Bridging-Header-Datei Eines macOS 10.13- oder iOS 11-Projekts folgende Definition hinzu:

#import <Foundation/Foundation.h>

typedef NS_ENUM(NSInteger, MyEnum)
{
    MyEnumA = 1,
    MyEnumB = 2,
    MyEnumC NS_ENUM_DEPRECATED(10_10, 10_13, 8_0, 11_0, "use MyEnumNewC") = 3,

    MyEnumNewC NS_ENUM_AVAILABLE(10_13, 11_0) = 3,
};

Dies wird in Swift als importiert

 public enum MyEnum : Int {
    case A
    case B
    @available(OSX, introduced: 10_10, deprecated: 10_13, message: "use MyEnumNewC")
    case C

    @available(OSX 10_13, *)
    public static var newC: MyEnum { get }
 }

mit 3 Fällen für den ersten (eindeutigen) Listenwert und eine staticproperty für den doppelten Wert.

Tatsächlich löst jede Verwendung von MyEnum eine Warnung vor Ablehnung aus:

// main.Swift:
print(MyEnum.A) // Or: let _: MyEnum? = nil

// Build log:
// <unknown>:0: warning: 'C' was deprecated in OS X 10.13: use MyEnumNewC

Außerdem ist es nicht möglich, den neuen Aufzählungswert in einer Switch-Anweisung zu verwenden:

func foo(err: MyEnum) {
    switch err {
    case .A:
        print("A")
    case .B:
        print("B")
    case .newC:
        print("C")
    }
}

// Build log:
// main.Swift:12:9: error: switch must be exhaustive
// <unknown>:0: warning: 'C' was deprecated in OS X 10.13: use MyEnumNewC

auch wenn der Compiler (anscheinend) weiß, dass diese Fälle erschöpfend sind:

func foo(err: MyEnum) {
    switch err { // Switch must be exhaustive
    case .A:
        print("A")
    case .B:
        print("B")
    case .newC:
        print("C")
    default:
        print("default")
    }
}

// Build log:
// <unknown>:0: warning: 'C' was deprecated in OS X 10.13: use MyEnumNewC
// main.Swift:19:9: warning: default will never be executed

Das sieht für mich nach einem Compiler-Fehler aus.

21
Martin R

Ja, dies sind neue Warnungen, die angezeigt werden, wenn Apple zu iOS 11 und FaceID wechselt. Wahrscheinlich prüfen Sie, ob die biometrische Hardware nicht gesperrt ist, Fingerabdrücke registriert wurden und das Gerät über die unterstützende Hardware verfügt.

Hier ein Beispiel:

import LocalAuthentication

...

var authContext = LAContext()
var biometricsError: NSError?
authContext?.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &biometricsError)

Bis zu iOS 10 würde man folgende Überprüfungen durchführen:

if biometricsError?.code == LAError.touchIDNotAvailable.rawValue {
  // No hardware
}

if biometricsError?.code == LAError.touchIDNotEnrolled.rawValue {
  // No fingerprints
}

if biometricsError?.code == LAError.touchIDLockout.rawValue {
  // Locked out
}

Hinweis: iOS 11 hat eine geringfügige Variante des obigen Codes eingeführt. Anstatt LAError.touchID für jede Fehlereigenschaft zu verwenden, wurde LAError.biometry eingeführt. Daher hätten Sie: biometryNotAvailable, biometryNotEnrolled und biometryLockout.

Apple scheint diesen Ansatz zu bevorzugen:

if biometricsError?.code == Int(kLAErrorBiometryNotAvailable) {
  // No hardware
}

if biometricsError?.code == Int(kLAErrorBiometryNotEnrolled) {
  // No fingerprints
}

if biometricsError?.code == Int(kLAErrorBiometryLockout) {
  // Locked out
}

Diese Methode entfernt die Warnungen von Xcode.

7
Oliver Spryn

Wie bereits erwähnt, ist dies ein Fehler im Compiler. Das Swift-Team ist sich dessen bewusst und Sie möchten vielleicht für den Fehler stimmen . Fügen Sie gleichzeitig eine Uhr hinzu, damit Sie die folgende Problemumgehung entfernen können, wenn sie behoben wurde.

Um die Warnungen nicht zu erhalten, müssen Sie Folgendes tun: LAError nicht erwähnen. Stellen Sie sich LAError als Voldemort vor. 

Verwenden Sie stattdessen die Objective-C-Stilfehlerprüfung. Alle Error-Enums werden einer NSError zugeordnet, die aus einer Domäne und einem Code aufgebaut ist. Die Konstanten, mit denen sie verglichen werden sollen, werden ebenfalls nach Swift exportiert. Sie können ohne Warnungen benannt werden. So könnte Ihr Code ein wenig (hoffentlich sehr wenig) so aussehen.

let context = LAContext()
let text = "Authenticate, please!"
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: text) { (success, error) in
    if success {
        print("????")
    } else {
        guard let error = error else {
            return print("Should not happen according to the docs!")
        }
        let nsError = error as NSError
        switch nsError.domain {
        case kLAErrorDomain:
            switch nsError.code {
            case Int(kLAErrorUserCancel):
                print("User cancelled.")
            case Int(kLAErrorBiometryLockout):
                print("Biometry lockout.")
            default:
                print("Unhandled error.")
            }
        default:
            print("Unhandled error domain. Probably will not happen.")
        }
    }
}
4
skagedal

Auch ich hatte lange Zeit damit zu kämpfen. Olivers Antwort führte mich zu einer Lösung, die für mich funktionierte, aber für den Fall, dass andere dieses Problem immer noch haben - es scheint, dass JEDER Verweis auf die alten LAError-Werte die oben aufgeführten Warnungen auslösen wird.

Dieser einfache Code erzeugt beispielsweise die Warnungen. Entfernen Sie ALLE Verweise auf die alten Codes und verwenden Sie Olivers Ansatz.

func evaluateAuthenticationPolicyMessageForLA(errorCode: Int) -> String {
    var message = ""

    switch errorCode {
    case LAError.authenticationFailed.rawValue:
        message = "The user failed to provide valid credentials"
    default:
        message = "Can't use any version of old LAError"
    }

    return message
}//evaluateAuthenticationPolicyMessageForLA

In der Tat kann es noch einfacher sein. Versuche dies:

func evaluateAuthenticationPolicyMessageForBiometricsError(biometricsError: Int) -> String {

    var message = "I would normally leave this blank"

    if biometricsError == kLAErrorBiometryNotAvailable {
        message = "Biometrics are not available on this device"
    }//if not avail

    if biometricsError == kLAErrorBiometryNotEnrolled {
        message = "Biometrics are not enrolled on this device"
    }//if not enrolled

    if biometricsError == kLAErrorBiometryLockout {
        message = "Biometrics are locked out on this device"
    }//if locked out

    return message

}//evaluateAuthenticationPolicyMessageForBiometricsError
0
user2698617