web-dev-qa-db-ja.com

touchIDLockoutはiOS 11.0で廃止予定

アプリケーションをIOS11のXcode 9でコンパイルすると、次の警告が表示されます。

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

TouchIDを使用していますが、touchIdLockout ... csteを使用しておらず、touchIDは正しく機能しています。

これらの警告を削除するにはどうすればよいですか?


編集(元の作者によるものではありません):

これを1つの原因にまで追跡しました。これらの警告を表示するには、コード内のLocalAuthenticationフレームワークからLAErrorを参照するだけで十分です。

再現手順(Xcode 9.2で試行):

  1. 新しいiOSアプリ(シングルビューテンプレート)を作成します。 iOS展開ターゲットがiOS 11.2に設定されていることに注意してください。
  2. これらの行をAppDelegate.Swiftに追加します。

    import LocalAuthentication
    

    appDidFinishLaunchingの1行:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        let _: LAError? = nil
        return true
    }
    
  3. アプリをビルドします。

let _: LAError? = nil行は、3つの警告を表示するのに十分です。ただし、警告は特定のコード行には関連付けられていません。それらはファイル/行参照なしでビルドログに表示されます。

<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

スクリーンショットは次のとおりです:Xcodeの警告のスクリーンショット

そしてサンプルプロジェクト:ダウンロード用サンプルプロジェクト(Xcode 9.2)

参考までに、これをアップルに報告しました。レーダー#36028653。

19
sebastien

短い答え:同じ値を持つ複数の定数を定義するC列挙のインポートが原因で、コンパイラのバグのように見えます。

長い答え:残念ながら、非推奨の警告を回避する方法はありません。原因の可能性のある説明のみです。

LAErrorコードは、LocalAuthenticationフレームワークの<LAError.h>のC列挙として定義されています。以下はその定義の抜粋です。

// 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);

「古い」(非推奨)エラーコードと「新しい」エラーコードが同じ値を使用していることがわかります。たとえば、LAErrorTouchIDNotAvailableLAErrorBiometryNotAvailableはどちらも-6として定義されます。

これはCでは完全に有効ですが、a Swift enumの生の値は相互に異なる必要があります。明らかに、Swiftインポーターは新規/重複ケースを静的変数にマッピングします。

Swiftマッピングの抜粋です:

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 }
        // ...
    }

    // ...
}

そして、これが非推奨警告の原因であり、Swift-usersメーリングリストで報告された問題の原因でもあるようです。

LAErrorの完全かつ警告のないswitchステートメントを書くことは不可能であること。


私の推測を証明するために、カスタム列挙で問題を再現しました。次の定義をmacOS 10.13またはiOS 11プロジェクトのブリッジングヘッダーファイルに追加します。

#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,
};

これはSwiftとしてインポートされます

 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 }
 }

最初の(個別の)列挙値の3つのケースと、重複する値の静的プロパティ。

そして実際、MyEnumを使用すると、非推奨の警告がトリガーされます。

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

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

さらに、switchステートメントで新しい列挙値を使用することはできません。

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

コンパイラが(どうやら)これらのケースが完全であることを知っているとしても:

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

これはコンパイラのバグのようです。

23
Martin R

はい、これらはAppleがiOS 11とFaceIDに移行するために表示される新しい警告です。ほとんどの場合、生体認証ハードウェアがロックアウトされていないか、指紋が登録されているか、デバイスにはサポートハードウェアがあります。

以下は設定例です。

import LocalAuthentication

...

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

IOS 10までは、次のようなチェックを実行します。

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

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

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

注: iOS 11では、上記のコードのわずかなバリアントが導入されました。各エラープロパティにLAError.touchIDを使用する代わりに、LAError.biometryを導入しました。したがって、次のようになります。biometryNotAvailablebiometryNotEnrolled、およびbiometryLockout

代わりに、Appleはこのアプローチを好むようです:

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

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

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

このメソッドは、Xcodeの警告を取り除きます。

7
Oliver Spryn

既に述べたように、これはコンパイラーのバグです。 Swiftチームは認識しており、移動したい場合があります バグに投票 。同時に、それにウォッチを追加して、以下を削除できるようにします修正された場合の回避策。

警告を受け取らないようにするために必要なことは次のとおりです:_LAErrorについて言及しないでください。 LAErrorをヴォルデモートと考えてください。

代わりに、Objective-Cスタイルのエラーチェックを使用します。すべてのError列挙型は、ドメインとコードから構築されたNSErrorにマップされます。これらを比較する定数もSwiftにエクスポートされます。警告なしに名前を付けることができます。したがって、コードは次のように少し(できれば非常に少なく)見えるかもしれません。

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.")
        }
    }
}
5
skagedal

私も非常に長い間これに苦労しました。 Oliverの答えは私に有効な解決策を導きましたが、まだこの問題を抱えている他の人がいる場合に備えて-古いLAError値を参照すると、上記の警告が生成されるようです。

たとえば、この単純なコードは警告を生成します。古いコードへの参照をすべて削除し、オリバーのアプローチを使用します。

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

実際、それはさらに簡単になる可能性があります。これを試して:

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