Last active
April 23, 2025 11:28
-
-
Save ArtCC/4026fb66417d8d9475a8724b4fb4fe9e to your computer and use it in GitHub Desktop.
BiometricManager (Swift 6 compatibility)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import LocalAuthentication | |
| @MainActor | |
| protocol BiometricManagerProtocol: Sendable { | |
| func biometricType() -> BiometricManager.BiometricType | |
| func isBiometricAvailable() -> Bool | |
| func authenticate(reason: String?) async throws -> Bool | |
| func updateLoginReason(_ newReason: String) | |
| } | |
| @MainActor | |
| final class BiometricManager: BiometricManagerProtocol { | |
| // MARK: - Properties | |
| enum BiometricType: String, Sendable, CaseIterable { | |
| case faceID | |
| case opticID | |
| case touchID | |
| case unknown | |
| } | |
| static let shared = BiometricManager() | |
| private var loginReason: String | |
| // MARK: - Init | |
| private init() { | |
| self.loginReason = "Authenticate to access" | |
| } | |
| // MARK: - Public functions | |
| func biometricType() -> BiometricType { | |
| let context = LAContext() | |
| var error: NSError? | |
| guard context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) else { | |
| return .unknown | |
| } | |
| if #available(iOS 11.0, *) { | |
| switch context.biometryType { | |
| case .none: | |
| return .unknown | |
| case .touchID: | |
| return .touchID | |
| case .faceID: | |
| return .faceID | |
| case .opticID: | |
| return .opticID | |
| @unknown default: | |
| return .unknown | |
| } | |
| } else { | |
| return .touchID | |
| } | |
| } | |
| func isBiometricAvailable() -> Bool { | |
| let context = LAContext() | |
| var error: NSError? | |
| return context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) | |
| } | |
| func authenticate(reason: String?) async throws -> Bool { | |
| let context = LAContext() | |
| let authReason = reason ?? loginReason | |
| let policy: LAPolicy = .deviceOwnerAuthentication | |
| return try await withCheckedThrowingContinuation { [context] continuation in | |
| context.evaluatePolicy(policy, localizedReason: authReason) { success, error in | |
| continuation.resume(with: Result { | |
| if success { | |
| return true | |
| } else if let error { | |
| throw error | |
| } else { | |
| throw LAError(.appCancel) | |
| } | |
| }) | |
| } | |
| } | |
| } | |
| func updateLoginReason(_ newReason: String) { | |
| loginReason = newReason | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment