BLBiometricAuth imports LocalAuthentication (unavailable on watchOS). BLCrashReporter imports MetricKit (unavailable on watchOS). Package.swift declares watchOS 10+ as a platform target. Fix: wrap both files in #if canImport() guards. BLCrashReport model struct stays outside the guard (data-only, all platforms).
78 lines
2.6 KiB
Swift
78 lines
2.6 KiB
Swift
// ── Biometric Authentication ────────────────────────────────
|
|
// Generic Face ID / Touch ID wrapper using LocalAuthentication.
|
|
// Product apps pass a custom reason string for the biometric prompt.
|
|
// Not available on watchOS — guarded with #if canImport.
|
|
|
|
import Foundation
|
|
|
|
#if canImport(LocalAuthentication)
|
|
import LocalAuthentication
|
|
|
|
/// Generic biometric authentication for all ByteLyst iOS/macOS apps.
|
|
/// Not available on watchOS (LocalAuthentication is iOS/macOS only).
|
|
public enum BLBiometricAuth {
|
|
|
|
public enum BiometricType {
|
|
case faceID, touchID, none
|
|
}
|
|
|
|
/// Check what biometric type is available on this device.
|
|
public static var availableType: BiometricType {
|
|
let context = LAContext()
|
|
var error: NSError?
|
|
guard context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) else {
|
|
return .none
|
|
}
|
|
switch context.biometryType {
|
|
case .faceID: return .faceID
|
|
case .touchID: return .touchID
|
|
default: return .none
|
|
}
|
|
}
|
|
|
|
/// Whether biometric auth is available on this device.
|
|
public static var isAvailable: Bool {
|
|
availableType != .none
|
|
}
|
|
|
|
/// Whether the user has enabled biometric lock in settings.
|
|
/// Uses a configurable UserDefaults key.
|
|
public static func isEnabled(key: String = "biometric_lock_enabled") -> Bool {
|
|
UserDefaults.standard.bool(forKey: key)
|
|
}
|
|
|
|
/// Set biometric lock enabled state.
|
|
public static func setEnabled(_ enabled: Bool, key: String = "biometric_lock_enabled") {
|
|
UserDefaults.standard.set(enabled, forKey: key)
|
|
}
|
|
|
|
/// Authenticate with biometrics only. Returns true on success.
|
|
public static func authenticate(reason: String = "Unlock app") async -> Bool {
|
|
let context = LAContext()
|
|
context.localizedCancelTitle = "Use Password"
|
|
|
|
do {
|
|
return try await context.evaluatePolicy(
|
|
.deviceOwnerAuthenticationWithBiometrics,
|
|
localizedReason: reason
|
|
)
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
|
|
/// Authenticate with biometrics or device passcode fallback.
|
|
public static func authenticateWithPasscode(reason: String = "Unlock app") async -> Bool {
|
|
let context = LAContext()
|
|
do {
|
|
return try await context.evaluatePolicy(
|
|
.deviceOwnerAuthentication,
|
|
localizedReason: reason
|
|
)
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
#endif
|