Files
InvestmentTrackerApp/PortfolioJournal/Utilities/AppLockService.swift
T
alexandrev-tibco 6774d76146 Biometría genérica (Face ID / Touch ID / Optic ID) y What's New 1.7.0
- AppLockService.biometryKind lee LAContext.biometryType; textos e icono del
  bloqueo y de la privacidad de saldos ya no asumen Face ID (Duo puede llevar
  Touch ID). Nuevas claves biometric_* en los 7 idiomas.
- Entrada 1.7.0 en el catálogo What's New (Duo, inspector, biometría) con
  strings en los 7 idiomas.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F1u4K16xy7eQVtgsYNZ9Vn
2026-09-16 11:44:50 +02:00

68 lines
2.2 KiB
Swift

import Foundation
import LocalAuthentication
/// Biometric hardware available on this device. Never assume Face ID: iPad and
/// iPhone Duo can ship with Touch ID, Vision Pro with Optic ID.
enum BiometryKind {
case faceID
case touchID
case opticID
case none
/// Marketing name shown in UI ("Face ID", "Touch ID", "Optic ID"). Falls back
/// to a generic label when no biometry is available (e.g. not enrolled).
var displayName: String {
switch self {
case .faceID: return "Face ID"
case .touchID: return "Touch ID"
case .opticID: return "Optic ID"
case .none: return String(localized: "biometric_generic_name")
}
}
/// SF Symbol matching the hardware.
var systemImage: String {
switch self {
case .faceID: return "faceid"
case .touchID: return "touchid"
case .opticID: return "opticid"
case .none: return "lock.shield"
}
}
}
enum AppLockService {
static func canUseBiometrics() -> Bool {
let context = LAContext()
var error: NSError?
return context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)
}
/// The biometry type reported by the system. `biometryType` is only populated
/// after `canEvaluatePolicy` runs, and stays set even when not enrolled.
static var biometryKind: BiometryKind {
let context = LAContext()
var error: NSError?
_ = context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)
switch context.biometryType {
case .faceID: return .faceID
case .touchID: return .touchID
case .opticID: return .opticID
case .none: return .none
@unknown default: return .none
}
}
/// Localized biometry name for user-facing text.
static var biometryName: String { biometryKind.displayName }
static func authenticate(reason: String, completion: @escaping (Bool) -> Void) {
let context = LAContext()
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, _ in
DispatchQueue.main.async {
completion(success)
}
}
}
}