Как обрабатывать touchID при загрузке приложения из фона Swift

Я реализую возможность входа в систему с помощью touchID с помощью Swift. Далее: при запуске приложения появляется экран входа в систему и всплывающее окно touchID - все работает нормально. Проблема возникает, когда приложение загружается из фона: я хочу, чтобы всплывающее окно touchID появлялось над экраном входа, если определенный временной интервал еще не превышен, но на этот раз я хочу, чтобы touchID перешел в последний показанный вид перед тем, как приложение перешло в фоновый режим. (то есть, если пользователь хочет отменить touchID, под ним находится экран входа в систему, где он затем может пройти аутентификацию с помощью пароля, что приведет его к последнему показанному представлению ИЛИ, если аутентификация touchID прошла успешно, экран входа в систему должен быть отклонен и представлен последний показанный вид.) Я действительно пробовал все самостоятельно и искал ответы - мне ничего не помогло. Вот мой код:

override func viewDidLoad() {
    super.viewDidLoad()
    //notify when foreground or background have been entered -> in that case there are two methods that will be invoked: willEnterForeground and didEnterBackground
    let notificationCenter = NSNotificationCenter.defaultCenter()
    notificationCenter.addObserver(self, selector: "willEnterForeground", name:UIApplicationWillEnterForegroundNotification, object: nil)
    notificationCenter.addObserver(self, selector: "didEnterBackground", name: UIApplicationDidEnterBackgroundNotification, object: nil)
    password.secureTextEntry = true
    if (username != nil) {
        username.text = "bucketFit"
    }
    username.delegate = self
    password.delegate = self

    if let alreadyShown : AnyObject? = def.objectForKey("alreadyShown") {
        if (alreadyShown == nil){
            authenticateWithTouchID()
        }
    }
}

willEnterForeground:

func willEnterForeground() {
    //save locally that the guide already logged in once and the application is just entering foreground
    //the variable alreadyShown is used for presenting the touchID, see viewDidAppear method
    def.setObject(true, forKey: "alreadyShown")
    if let backgroundEntered : AnyObject? = def.objectForKey("backgroundEntered") {
        let startTime = backgroundEntered as! NSDate
        //number of seconds the app was in the background
        let inactivityDuration = NSDate().timeIntervalSinceDate(startTime)
        //if the app was longer than 3 minutes inactiv, ask the guide to input his password
        if (inactivityDuration > 2) {
            showLoginView()
        } else {
            def.removeObjectForKey("alreadyShown")
            showLoginView()
        }
    }
}

AuthenticateWithTouchID ():

func authenticateWithTouchID() {
    let context : LAContext = LAContext()
    context.localizedFallbackTitle = ""
    var error : NSError?
    let myLocalizedReasonString : NSString = "Authentication is required"
    //check whether the iphone has the touchID possibility at all
    if context.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error) {
        //if yes then execute the touchID and see whether the finger print matches
        context.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: myLocalizedReasonString as String, reply: { (success : Bool, evaluationError : NSError?) -> Void in
            //touchID succeded -> go to students list page
            if success {
                NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
                    self.performSegueWithIdentifier("studentsList", sender: self)
                })
            } else {
                // Authentification failed
                print(evaluationError?.description)
                //print out the specific error
                switch evaluationError!.code {
                case LAError.SystemCancel.rawValue:
                    print("Authentication cancelled by the system")
                case LAError.UserCancel.rawValue:
                    print("Authentication cancelled by the user")
                default:
                    print("Authentication failed")
                }
            }
        })
    }
}

shouldPerformSegueWithIdentifier:

override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject?) -> Bool {
    if (false) { //TODO -> username.text!.isEmpty || password.text!.isEmpty
        notify("Login failed", message: "Please enter your username and password to proceed")
        return false
    } else if (false) { //TODO when backend ready! -> !login("bucketFit", password: "test")
        notify("Incorrect username or password", message: "Please try again")
        return false
        //if the login page is loaded after background, dont proceed (then we need to present the last presented view on the stack before the app leaved to background)
    } else if let alreadyShown : AnyObject? = def.objectForKey("alreadyShown") {
        if (alreadyShown != nil){
            //TODO check whether login data is correct
            dismissLoginView()
            return false
        }
    }

    return true
}

Заранее благодарю.


person Aldiyana    schedule 13.12.2015    source источник


Ответы (1)


Что вы могли бы сделать, так это создать AuthenticationManager. Этот менеджер будет общим экземпляром, который отслеживает необходимость обновления аутентификации. Вы также можете захотеть, чтобы он содержал все методы аутентификации.

class AuthenticationManager {
  static let sharedInstance = AuthenticationManager()
  var needsAuthentication = false
}

В AppDelegate:

func willEnterForeground() {
    def.setObject(true, forKey: "alreadyShown")
    if let backgroundEntered : AnyObject? = def.objectForKey("backgroundEntered") {
        let startTime = backgroundEntered as! NSDate
        //number of seconds the app was in the background
        let inactivityDuration = NSDate().timeIntervalSinceDate(startTime)
        //if the app was longer than 3 minutes inactiv, ask the guide to input his password
        if (inactivityDuration > 2) {
            AuthenticationManager.sharedInstance.needsAuthentication = true
        }
    }
}

Затем создайте подкласс UIViewController с контроллером представления с именем SecureViewController. Переопределить viewDidLoad () в этом подклассе

override fun viewDidLoad() {
  super.viewDidLoad()
  if (AuthenticationManager.sharedInstance().needsAuthentication) {
    // call authentication methods
  }
}

Теперь сделайте все ваши контроллеры представления, требующие аутентификации, подклассами SecureViewController.

person tfrancis    schedule 12.03.2016