【问题标题】:How to handle touchID when loading app from background Swift从后台 Swift 加载应用程序时如何处理 touchID
【发布时间】:2015-12-13 08:41:29
【问题描述】:

我正在使用 Swift 实现使用 touchID 的登录可能性。 以下:当应用程序启动时,有一个登录屏幕和一个 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
}

提前致谢。

【问题讨论】:

    标签: ios swift touch-id


    【解决方案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
            }
        }
    }
    

    然后,使用名为 SecureViewController 的视图控制器子类化 UIViewController。在这个子类中覆盖 viewDidLoad()

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

    现在,制作所有需要 SecureViewController 身份验证子类的视图控制器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-31
      • 2020-10-03
      • 1970-01-01
      相关资源
      最近更新 更多