我在我的应用程序的日志功能中使用了github的PasscodeLock swift源代码。我使用密码允许用户锁定日记,以便人们无法打开应用程序并阅读他们的条目。
我项目中的.xib文件是应该显示的实际密码锁定屏幕。附加的PasscodeLockPresenter.swift文件是负责在现有窗口上呈现视图控制器并呈现锁定屏幕的文件。锁定屏幕也启用了触摸ID。当我进入应用程序的屏幕时应该显示锁定屏幕时,会出现Touch ID提示,但没有锁屏视图控制器。我该如何解决这个问题?这只是一个错误吗?
PasscodeLockPresenter.swift
wire.endTransmission
PasscodeLockViewController.swift
import UIKit
open class PasscodeLockPresenter {
fileprivate var mainWindow: UIWindow?
fileprivate lazy var passcodeLockWindow: UIWindow = {
let window = UIWindow(frame: UIScreen.main.bounds)
window.windowLevel = 0
window.makeKeyAndVisible()
return window
}()
fileprivate let passcodeConfiguration: PasscodeLockConfigurationType
open var isPasscodePresented = false
open let passcodeLockVC: PasscodeLockViewController
public init(mainWindow window: UIWindow?, configuration: PasscodeLockConfigurationType, viewController: PasscodeLockViewController) {
mainWindow = window
mainWindow?.windowLevel = 1
passcodeConfiguration = configuration
passcodeLockVC = viewController
}
public convenience init(mainWindow window: UIWindow?, configuration: PasscodeLockConfigurationType) {
let passcodeLockVC = PasscodeLockViewController(state: .enterPasscode, configuration: configuration)
self.init(mainWindow: window, configuration: configuration, viewController: passcodeLockVC)
}
open func presentPasscodeLock() {
guard passcodeConfiguration.repository.hasPasscode else { return }
guard !isPasscodePresented else { return }
isPasscodePresented = true
passcodeLockWindow.windowLevel = 2
passcodeLockWindow.isHidden = false
mainWindow?.windowLevel = 1
mainWindow?.endEditing(true)
let passcodeLockVC = PasscodeLockViewController(state: .enterPasscode, configuration: passcodeConfiguration)
let userDismissCompletionCallback = passcodeLockVC.dismissCompletionCallback
passcodeLockVC.dismissCompletionCallback = { [weak self] in
userDismissCompletionCallback?()
self?.dismissPasscodeLock()
}
passcodeLockWindow.rootViewController = passcodeLockVC
}
open func dismissPasscodeLock(animated: Bool = true) {
isPasscodePresented = false
mainWindow?.windowLevel = 1
mainWindow?.makeKeyAndVisible()
if animated {
animatePasscodeLockDismissal()
} else {
passcodeLockWindow.windowLevel = 0
passcodeLockWindow.rootViewController = nil
}
}
internal func animatePasscodeLockDismissal() {
UIView.animate(
withDuration: 0.5,
delay: 0,
usingSpringWithDamping: 1,
initialSpringVelocity: 0,
options: UIViewAnimationOptions(),
animations: { [weak self] in
self?.passcodeLockWindow.alpha = 0
},
completion: { [weak self] _ in
self?.passcodeLockWindow.windowLevel = 0
self?.passcodeLockWindow.rootViewController = nil
self?.passcodeLockWindow.alpha = 1
}
)
}
}
EnterPasscodeState.swift
import UIKit
open class PasscodeLockViewController: UIViewController, PasscodeLockTypeDelegate {
public enum LockState {
case enterPasscode
case setPasscode
case changePasscode
case removePasscode
func getState() -> PasscodeLockStateType {
switch self {
case .enterPasscode: return EnterPasscodeState()
case .setPasscode: return SetPasscodeState()
case .changePasscode: return ChangePasscodeState()
case .removePasscode: return EnterPasscodeState(allowCancellation: true)
}
}
}
@IBOutlet open weak var titleLabel: UILabel?
@IBOutlet open weak var descriptionLabel: UILabel?
@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 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 let passcodeLock: PasscodeLockType
internal var isPlaceholdersAnimationCompleted = true
fileprivate var shouldTryToAuthenticateWithBiometrics = true
// MARK: - Initializers
public init(state: PasscodeLockStateType, configuration: PasscodeLockConfigurationType, animateOnDismiss: Bool = true) {
self.animateOnDismiss = animateOnDismiss
passcodeConfiguration = configuration
passcodeLock = PasscodeLock(state: state, configuration: configuration)
let nibName = "PasscodeLockView"
let bundle: Bundle = bundleForResource(nibName, ofType: "nib")
super.init(nibName: nibName, bundle: bundle)
passcodeLock.delegate = self
notificationCenter = NotificationCenter.default
}
public convenience init(state: LockState, configuration: PasscodeLockConfigurationType, animateOnDismiss: Bool = true) {
self.init(state: state.getState(), configuration: configuration, animateOnDismiss: animateOnDismiss)
}
public required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
clearEvents()
}
// MARK: - View
open override func viewDidLoad() {
super.viewDidLoad()
updatePasscodeView()
deleteSignButton?.isEnabled = false
setupEvents()
}
open override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if shouldTryToAuthenticateWithBiometrics {
authenticateWithBiometrics()
}
}
internal func updatePasscodeView() {
titleLabel?.text = passcodeLock.state.title
descriptionLabel?.text = passcodeLock.state.description
cancelButton?.isHidden = !passcodeLock.state.isCancellableAction
touchIDButton?.isHidden = !passcodeLock.isTouchIDAllowed
}
// MARK: - Events
fileprivate func setupEvents() {
notificationCenter?.addObserver(self, selector: #selector(PasscodeLockViewController.appWillEnterForegroundHandler(_:)), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
notificationCenter?.addObserver(self, selector: #selector(PasscodeLockViewController.appDidEnterBackgroundHandler(_:)), name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil)
}
fileprivate func clearEvents() {
notificationCenter?.removeObserver(self, name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
notificationCenter?.removeObserver(self, name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil)
}
open func appWillEnterForegroundHandler(_ notification: Notification) {
authenticateWithBiometrics()
}
open func appDidEnterBackgroundHandler(_ notification: Notification) {
shouldTryToAuthenticateWithBiometrics = false
}
// MARK: - Actions
@IBAction func passcodeSignButtonTap(_ sender: PasscodeSignButton) {
guard isPlaceholdersAnimationCompleted else { return }
passcodeLock.addSign(sender.passcodeSign)
}
@IBAction func cancelButtonTap(_ sender: UIButton) {
dismissPasscodeLock(passcodeLock)
}
@IBAction func deleteSignButtonTap(_ sender: UIButton) {
passcodeLock.removeSign()
}
@IBAction func touchIDButtonTap(_ sender: UIButton) {
passcodeLock.authenticateWithBiometrics()
}
fileprivate func authenticateWithBiometrics() {
if passcodeConfiguration.shouldRequestTouchIDImmediately && passcodeLock.isTouchIDAllowed {
passcodeLock.authenticateWithBiometrics()
}
}
internal func dismissPasscodeLock(_ lock: PasscodeLockType, completionHandler: (() -> Void)? = nil) {
// if presented as modal
if presentingViewController?.presentedViewController == self {
dismiss(animated: animateOnDismiss, completion: { [weak self] _ in
self?.dismissCompletionCallback?()
completionHandler?()
})
return
// if pushed in a navigation controller
} else if navigationController != nil {
navigationController?.popViewController(animated: animateOnDismiss)
}
dismissCompletionCallback?()
completionHandler?()
}
// MARK: - Animations
internal func animateWrongPassword() {
deleteSignButton?.isEnabled = false
isPlaceholdersAnimationCompleted = false
animatePlaceholders(placeholders, toState: .error)
placeholdersX?.constant = -40
view.layoutIfNeeded()
UIView.animate(
withDuration: 0.5,
delay: 0,
usingSpringWithDamping: 0.2,
initialSpringVelocity: 0,
options: [],
animations: {
self.placeholdersX?.constant = 0
self.view.layoutIfNeeded()
},
completion: { completed in
self.isPlaceholdersAnimationCompleted = true
self.animatePlaceholders(self.placeholders, toState: .inactive)
})
}
internal func animatePlaceholders(_ placeholders: [PasscodeSignPlaceholderView], toState state: PasscodeSignPlaceholderView.State) {
for placeholder in placeholders {
placeholder.animateState(state)
}
}
fileprivate func animatePlacehodlerAtIndex(_ index: Int, toState state: PasscodeSignPlaceholderView.State) {
guard index < placeholders.count && index >= 0 else { return }
placeholders[index].animateState(state)
}
// MARK: - PasscodeLockDelegate
open func passcodeLockDidSucceed(_ lock: PasscodeLockType) {
deleteSignButton?.isEnabled = true
animatePlaceholders(placeholders, toState: .inactive)
dismissPasscodeLock(lock, completionHandler: { [weak self] _ in
self?.successCallback?(lock)
})
}
open func passcodeLockDidFail(_ lock: PasscodeLockType) {
animateWrongPassword()
}
open func passcodeLockDidChangeState(_ lock: PasscodeLockType) {
updatePasscodeView()
animatePlaceholders(placeholders, toState: .inactive)
deleteSignButton?.isEnabled = false
}
open func passcodeLock(_ lock: PasscodeLockType, addedSignAtIndex index: Int) {
animatePlacehodlerAtIndex(index, toState: .active)
deleteSignButton?.isEnabled = true
}
open func passcodeLock(_ lock: PasscodeLockType, removedSignAtIndex index: Int) {
animatePlacehodlerAtIndex(index, toState: .inactive)
if index == 0 {
deleteSignButton?.isEnabled = false
}
}
}
PasscodeLock.swift
import Foundation
public let PasscodeLockIncorrectPasscodeNotification = "passcode.lock.incorrect.passcode.notification"
struct EnterPasscodeState: PasscodeLockStateType {
let title: String
let description: String
let isCancellableAction: Bool
var isTouchIDAllowed = true
fileprivate var inccorectPasscodeAttempts = 0
fileprivate var isNotificationSent = false
init(allowCancellation: Bool = false) {
isCancellableAction = allowCancellation
title = localizedStringFor("PasscodeLockEnterTitle", comment: "Enter passcode title")
description = localizedStringFor("PasscodeLockEnterDescription", comment: "Enter passcode description")
}
mutating func acceptPasscode(_ passcode: [String], fromLock lock: PasscodeLockType) {
guard let currentPasscode = lock.repository.passcode else {
return
}
if passcode == currentPasscode {
lock.delegate?.passcodeLockDidSucceed(lock)
} else {
inccorectPasscodeAttempts += 1
if inccorectPasscodeAttempts >= lock.configuration.maximumInccorectPasscodeAttempts {
postNotification()
}
lock.delegate?.passcodeLockDidFail(lock)
}
}
fileprivate mutating func postNotification() {
guard !isNotificationSent else { return }
let center = NotificationCenter.default
center.post(name: Notification.Name(rawValue: PasscodeLockIncorrectPasscodeNotification), object: nil)
isNotificationSent = true
}
}
非常感谢你!
另外,我在tableviewcontroller上使用此代码尝试显示.xib锁屏
import Foundation
import LocalAuthentication
open class PasscodeLock: PasscodeLockType {
open weak var delegate: PasscodeLockTypeDelegate?
open let configuration: PasscodeLockConfigurationType
open var repository: PasscodeRepositoryType {
return configuration.repository
}
open var state: PasscodeLockStateType {
return lockState
}
open var isTouchIDAllowed: Bool {
return isTouchIDEnabled() && configuration.isTouchIDAllowed && lockState.isTouchIDAllowed
}
fileprivate var lockState: PasscodeLockStateType
fileprivate lazy var passcode = [String]()
public init(state: PasscodeLockStateType, configuration: PasscodeLockConfigurationType) {
precondition(configuration.passcodeLength > 0, "Passcode length sould be greather than zero.")
self.lockState = state
self.configuration = configuration
}
open func addSign(_ sign: String) {
passcode.append(sign)
delegate?.passcodeLock(self, addedSignAtIndex: passcode.count - 1)
if passcode.count >= configuration.passcodeLength {
lockState.acceptPasscode(passcode, fromLock: self)
passcode.removeAll(keepingCapacity: true)
}
}
open func removeSign() {
guard passcode.count > 0 else { return }
passcode.removeLast()
delegate?.passcodeLock(self, removedSignAtIndex: passcode.count)
}
open func changeStateTo(_ state: PasscodeLockStateType) {
lockState = state
delegate?.passcodeLockDidChangeState(self)
}
open func authenticateWithBiometrics() {
guard isTouchIDAllowed else { return }
let context = LAContext()
let reason = NSLocalizedString("PasscodeLockTouchIDReason", comment: "TouchID authentication reason")
context.localizedFallbackTitle = localizedStringFor("PasscodeLockTouchIDButton", comment: "TouchID authentication fallback button")
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) {
success, error in
self.handleTouchIDResult(success)
}
}
fileprivate func handleTouchIDResult(_ success: Bool) {
DispatchQueue.main.async {
if success {
self.delegate?.passcodeLockDidSucceed(self)
}
}
}
fileprivate func isTouchIDEnabled() -> Bool {
let context = LAContext()
return context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil)
}
}
答案 0 :(得分:0)
您是否尝试过委托回VC或使用完成块,以便您的VC可以处理演示文稿?利用现有(viewController:animated :) API。
的最佳实践