diff --git a/PasscodeLock/PasscodeLock/ChangePasscodeState.swift b/PasscodeLock/PasscodeLock/ChangePasscodeState.swift index aefaacae..fd49d75b 100644 --- a/PasscodeLock/PasscodeLock/ChangePasscodeState.swift +++ b/PasscodeLock/PasscodeLock/ChangePasscodeState.swift @@ -13,7 +13,7 @@ struct ChangePasscodeState: PasscodeLockStateType { let title: String let description: String let isCancellableAction = true - var isTouchIDAllowed = false + var isBiometricAuthAllowed: Bool = false init() { diff --git a/PasscodeLock/PasscodeLock/ConfirmPasscodeState.swift b/PasscodeLock/PasscodeLock/ConfirmPasscodeState.swift index 371562b5..4ba6092f 100644 --- a/PasscodeLock/PasscodeLock/ConfirmPasscodeState.swift +++ b/PasscodeLock/PasscodeLock/ConfirmPasscodeState.swift @@ -13,7 +13,7 @@ struct ConfirmPasscodeState: PasscodeLockStateType { let title: String let description: String let isCancellableAction = true - var isTouchIDAllowed = false + var isBiometricAuthAllowed: Bool = false fileprivate var passcodeToConfirm: [String] diff --git a/PasscodeLock/PasscodeLock/EnterPasscodeState.swift b/PasscodeLock/PasscodeLock/EnterPasscodeState.swift index ebf8d2ec..78e70e5c 100644 --- a/PasscodeLock/PasscodeLock/EnterPasscodeState.swift +++ b/PasscodeLock/PasscodeLock/EnterPasscodeState.swift @@ -15,7 +15,7 @@ struct EnterPasscodeState: PasscodeLockStateType { let title: String let description: String let isCancellableAction: Bool - var isTouchIDAllowed = true + var isBiometricAuthAllowed = true static let incorrectPasscodeAttemptsKey = "incorrectPasscodeAttempts" static var incorrectPasscodeAttempts: Int { diff --git a/PasscodeLock/PasscodeLock/PasscodeLock.swift b/PasscodeLock/PasscodeLock/PasscodeLock.swift index cdcfdc84..d4489e21 100644 --- a/PasscodeLock/PasscodeLock/PasscodeLock.swift +++ b/PasscodeLock/PasscodeLock/PasscodeLock.swift @@ -22,8 +22,8 @@ open class PasscodeLock: PasscodeLockType { return lockState } - open var isTouchIDAllowed: Bool { - return isTouchIDEnabled() && configuration.isTouchIDAllowed && lockState.isTouchIDAllowed + open var isBiometricAuthAllowed: Bool { + return isBiometricAuthEnabled() && configuration.isBiometricAuthAllowed && lockState.isBiometricAuthAllowed } fileprivate var lockState: PasscodeLockStateType @@ -67,26 +67,37 @@ open class PasscodeLock: PasscodeLockType { open func authenticateWithBiometrics() { - guard isTouchIDAllowed else { return } + guard isBiometricAuthAllowed else { return } let context = LAContext() let reason: String - if let configReason = configuration.touchIdReason { + if let configReason = configuration.biometricAuthReason { reason = configReason } else { - reason = localizedStringFor("PasscodeLockTouchIDReason", comment: "TouchID authentication reason") + if #available(iOS 11, *) { + switch(context.biometryType) { + case .touchID: + reason = localizedStringFor("PasscodeLockTouchIDReason", comment: "Authentication required to proceed") + case .faceID: + reason = localizedStringFor("PasscodeLockFaceIDReason", comment: "Authentication required to proceed") + default: + reason = localizedStringFor("PasscodeLockBiometricAuthReason", comment: "Authentication required to proceed") + } + } else { + reason = localizedStringFor("PasscodeLockBiometricAuthReason", comment: "Authentication required to proceed") + } } - context.localizedFallbackTitle = localizedStringFor("PasscodeLockTouchIDButton", comment: "TouchID authentication fallback button") + context.localizedFallbackTitle = localizedStringFor("PasscodeLockBiometricAuthButton", comment: "Biometric authentication fallback button") context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, error in - self.handleTouchIDResult(success) + self.handleBiometricAuthResult(success) } } - fileprivate func handleTouchIDResult(_ success: Bool) { + fileprivate func handleBiometricAuthResult(_ success: Bool) { DispatchQueue.main.async { @@ -97,7 +108,7 @@ open class PasscodeLock: PasscodeLockType { } } - fileprivate func isTouchIDEnabled() -> Bool { + fileprivate func isBiometricAuthEnabled() -> Bool { let context = LAContext() diff --git a/PasscodeLock/PasscodeLock/SetPasscodeState.swift b/PasscodeLock/PasscodeLock/SetPasscodeState.swift index b43e4bbb..ee1108ea 100644 --- a/PasscodeLock/PasscodeLock/SetPasscodeState.swift +++ b/PasscodeLock/PasscodeLock/SetPasscodeState.swift @@ -13,7 +13,7 @@ struct SetPasscodeState: PasscodeLockStateType { let title: String let description: String let isCancellableAction = true - var isTouchIDAllowed = false + var isBiometricAuthAllowed: Bool = false init(title: String, description: String) { diff --git a/PasscodeLock/PasscodeLockViewController.swift b/PasscodeLock/PasscodeLockViewController.swift index 699e95c9..b6bcbdbf 100644 --- a/PasscodeLock/PasscodeLockViewController.swift +++ b/PasscodeLock/PasscodeLockViewController.swift @@ -32,14 +32,14 @@ open class PasscodeLockViewController: UIViewController, PasscodeLockTypeDelegat @IBOutlet open var placeholders: [PasscodeSignPlaceholderView] = [PasscodeSignPlaceholderView]() @IBOutlet open weak var cancelButton: UIButton? @IBOutlet open weak var deleteSignButton: UIButton? - @IBOutlet open weak var touchIDButton: UIButton? + @IBOutlet open weak var biometricAuthButton: UIButton! @IBOutlet open weak var placeholdersX: NSLayoutConstraint? open var successCallback: ((_ lock: PasscodeLockType) -> Void)? open var dismissCompletionCallback: (()->Void)? open var animateOnDismiss: Bool open var notificationCenter: NotificationCenter? - + internal let passcodeConfiguration: PasscodeLockConfigurationType internal var passcodeLock: PasscodeLockType internal var isPlaceholdersAnimationCompleted = true @@ -48,7 +48,7 @@ open class PasscodeLockViewController: UIViewController, PasscodeLockTypeDelegat // MARK: - Initializers - public init(state: PasscodeLockStateType, configuration: PasscodeLockConfigurationType, animateOnDismiss: Bool = true, nibName: String = "PasscodeLockView", bundle: Bundle? = nil) { + public init(state: PasscodeLockStateType, configuration: PasscodeLockConfigurationType, animateOnDismiss: Bool = true, nibName: String = "PasscodeLockView", bundle: Bundle? = nil) { self.animateOnDismiss = animateOnDismiss @@ -96,7 +96,7 @@ open class PasscodeLockViewController: UIViewController, PasscodeLockTypeDelegat open override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - if shouldTryToAuthenticateWithBiometrics && passcodeConfiguration.shouldRequestTouchIDImmediately { + if shouldTryToAuthenticateWithBiometrics && passcodeConfiguration.shouldRequestBiometricAuthImmediately { authenticateWithBiometrics() } @@ -107,7 +107,7 @@ open class PasscodeLockViewController: UIViewController, PasscodeLockTypeDelegat titleLabel?.text = passcodeLock.state.title descriptionLabel?.text = passcodeLock.state.description cancelButton?.isHidden = !passcodeLock.state.isCancellableAction - touchIDButton?.isHidden = !passcodeLock.isTouchIDAllowed + biometricAuthButton?.isHidden = !passcodeLock.isBiometricAuthAllowed } // MARK: - Events @@ -126,7 +126,7 @@ open class PasscodeLockViewController: UIViewController, PasscodeLockTypeDelegat @objc open func appWillEnterForegroundHandler(_ notification: Notification) { - if passcodeConfiguration.shouldRequestTouchIDImmediately { + if passcodeConfiguration.shouldRequestBiometricAuthImmediately { authenticateWithBiometrics() } } @@ -155,7 +155,7 @@ open class PasscodeLockViewController: UIViewController, PasscodeLockTypeDelegat passcodeLock.removeSign() } - @IBAction func touchIDButtonTap(_ sender: UIButton) { + @IBAction func biometricAuthButtonTap(_ sender: UIButton) { passcodeLock.authenticateWithBiometrics() } @@ -164,7 +164,7 @@ open class PasscodeLockViewController: UIViewController, PasscodeLockTypeDelegat guard passcodeConfiguration.repository.hasPasscode else { return } - if passcodeLock.isTouchIDAllowed { + if passcodeLock.isBiometricAuthAllowed { passcodeLock.authenticateWithBiometrics() } diff --git a/PasscodeLock/Protocols/PasscodeLockConfigurationType.swift b/PasscodeLock/Protocols/PasscodeLockConfigurationType.swift index 26daee2c..b702de2d 100644 --- a/PasscodeLock/Protocols/PasscodeLockConfigurationType.swift +++ b/PasscodeLock/Protocols/PasscodeLockConfigurationType.swift @@ -12,9 +12,9 @@ public protocol PasscodeLockConfigurationType { var repository: PasscodeRepositoryType {get} var passcodeLength: Int {get} - var isTouchIDAllowed: Bool {get set} - var shouldRequestTouchIDImmediately: Bool {get} - var touchIdReason: String? {get set} + var isBiometricAuthAllowed: Bool {get set} + var shouldRequestBiometricAuthImmediately: Bool {get} + var biometricAuthReason: String? {get set} var maximumInccorectPasscodeAttempts: Int {get} } diff --git a/PasscodeLock/Protocols/PasscodeLockStateType.swift b/PasscodeLock/Protocols/PasscodeLockStateType.swift index f246e2d9..bd208e32 100644 --- a/PasscodeLock/Protocols/PasscodeLockStateType.swift +++ b/PasscodeLock/Protocols/PasscodeLockStateType.swift @@ -13,7 +13,7 @@ public protocol PasscodeLockStateType { var title: String {get} var description: String {get} var isCancellableAction: Bool {get} - var isTouchIDAllowed: Bool {get} + var isBiometricAuthAllowed: Bool {get} mutating func acceptPasscode(_ passcode: [String], fromLock lock: PasscodeLockType) } diff --git a/PasscodeLock/Protocols/PasscodeLockType.swift b/PasscodeLock/Protocols/PasscodeLockType.swift index 434c87d6..46fc5149 100644 --- a/PasscodeLock/Protocols/PasscodeLockType.swift +++ b/PasscodeLock/Protocols/PasscodeLockType.swift @@ -14,7 +14,7 @@ public protocol PasscodeLockType { var configuration: PasscodeLockConfigurationType {get} var repository: PasscodeRepositoryType {get} var state: PasscodeLockStateType {get} - var isTouchIDAllowed: Bool {get} + var isBiometricAuthAllowed: Bool {get} func addSign(_ sign: String) func removeSign() diff --git a/PasscodeLock/Views/PasscodeLockView.xib b/PasscodeLock/Views/PasscodeLockView.xib index c17dae99..55afbfbb 100644 --- a/PasscodeLock/Views/PasscodeLockView.xib +++ b/PasscodeLock/Views/PasscodeLockView.xib @@ -1,18 +1,23 @@ - - + + + + + - + + + + - @@ -22,86 +27,99 @@ - + - + - + + + + + - + - + - + - + + + + - + - + - + - + + + + - + - + - + - + + + + - + - + - + - + @@ -111,28 +129,35 @@ + + + - + + + + + + + + + @@ -438,6 +495,7 @@ + diff --git a/PasscodeLock/en.lproj/PasscodeLock.strings b/PasscodeLock/en.lproj/PasscodeLock.strings index f71ef86c..f65e4dea 100755 --- a/PasscodeLock/en.lproj/PasscodeLock.strings +++ b/PasscodeLock/en.lproj/PasscodeLock.strings @@ -26,8 +26,10 @@ "PasscodeLockMismatchTitle" = "Try again"; "PasscodeLockMismatchDescription" = "Passcodes didn\'t match."; -/* Touch ID Reason */ +/* Biometric Auth Reason */ "PasscodeLockTouchIDReason" = "Authentication required to proceed"; +"PasscodeLockFaceIDReason" = "Authentication required to proceed"; +"PasscodeLockBiometricAuthReason" = "Authentication required to proceed"; -/* Touch ID Fallback Button */ -"PasscodeLockTouchIDButton" = "Enter Passcode"; \ No newline at end of file +/* Biometric Auth Fallback Button */ +"PasscodeLockBiometricAuthButton" = "Enter Passcode"; diff --git a/PasscodeLockDemo/CustomPasscodeLockPresenter.swift b/PasscodeLockDemo/CustomPasscodeLockPresenter.swift index 6436f782..6dd74d8e 100644 --- a/PasscodeLockDemo/CustomPasscodeLockPresenter.swift +++ b/PasscodeLockDemo/CustomPasscodeLockPresenter.swift @@ -52,7 +52,7 @@ class CustomPasscodeLockPresenter: PasscodeLockPresenter { } deinit { - // remove all notfication observers + // remove all notification observers notificationCenter.removeObserver(self) } @@ -73,19 +73,19 @@ class CustomPasscodeLockPresenter: PasscodeLockPresenter { // present PIN lock presentPasscodeLock() - // add splashView for iOS app background swithcer + // add splashView for iOS app background switcher addSplashView() } @objc dynamic func applicationDidBecomeActive() -> Void { - // remove splashView for iOS app background swithcer + // remove splashView for iOS app background switcher removeSplashView() } fileprivate func addSplashView() { - // add splashView for iOS app background swithcer + // add splashView for iOS app background switcher if isPasscodePresented { passcodeLockVC.view.addSubview(splashView) } else { @@ -97,7 +97,7 @@ class CustomPasscodeLockPresenter: PasscodeLockPresenter { fileprivate func removeSplashView() { - // remove splashView for iOS app background swithcer + // remove splashView for iOS app background switcher splashView.removeFromSuperview() } } diff --git a/PasscodeLockDemo/Info.plist b/PasscodeLockDemo/Info.plist index 0ca4d80e..1dfc027a 100644 --- a/PasscodeLockDemo/Info.plist +++ b/PasscodeLockDemo/Info.plist @@ -34,6 +34,8 @@ UIInterfaceOrientationPortrait + NSFaceIDUsageDescription + Face ID access is needed to authenticate using Face recognition. UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait diff --git a/PasscodeLockDemo/PasscodeLockConfiguration.swift b/PasscodeLockDemo/PasscodeLockConfiguration.swift index 2cfff32a..86ad607b 100644 --- a/PasscodeLockDemo/PasscodeLockConfiguration.swift +++ b/PasscodeLockDemo/PasscodeLockConfiguration.swift @@ -12,10 +12,10 @@ import PasscodeLock struct PasscodeLockConfiguration: PasscodeLockConfigurationType { let repository: PasscodeRepositoryType - var isTouchIDAllowed = true - let shouldRequestTouchIDImmediately = true - var touchIdReason: String? = nil - + var isBiometricAuthAllowed: Bool = true + let shouldRequestBiometricAuthImmediately: Bool = true + var biometricAuthReason: String? = nil + init(repository: PasscodeRepositoryType) { self.repository = repository