如何检测用户在UITextField

时间:2017-09-24 15:38:36

标签: ios uitextfield autofill uitextfielddelegate

我已经实现了在iOS 11上支持密码自动填充所需的所有应用和服务器更改,并且运行良好。我希望它能更好一点。

我的用户名和密码字段是UITextFields。我想确定用户何时“自动填充”了两个UITextField中的一个,因此我可以进入下一步。目前用户自动填充项目,然后需要按下屏幕键盘上的“下一步”按钮才能前进。我想代表用户触发此事。

WWDC2017密码自动填充会话说要使用UITextFieldTextDidChange。这有效,但当用户手动输入这些字段时,也会触发此操作。

我的想法是将文本的先前版本与文本的新版本进行比较,并假设如果长度从零增加到大于某个最小长度(2或更多),则用户使用自动填充。这应该在大多数情况下都有效,但是存在错误触发的风险(也许在慢速设备上快速键入)。所以对我来说,这可能是一个冒险的假设。

我很好奇是否有人找到了更加确定的方法来确定密码自动填充是否已在UITextField上使用,或者只是认为我对错误触发的担心是没有根据的。

8 个答案:

答案 0 :(得分:3)

不确定先前的答案是否在某个时候停止工作,但是我无法使其正常工作-使用自动填充功能时,我只会接到一个didBeginEditing呼叫。

但是,我确实找到了一种检测自动填充的方法。并且请记住,可以在输入一些字符后使用自动填充功能,例如,如果用户已经在电话号码中输入了一些数字,则他们会自动填充完整的数字。

对于Swift 4:

var rangeReplacedWithSpaceAt: Date?

var rangeReplacedWithSpace: NSRange?

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    // To detect AutoFill, look for two quick replacements. The first replaces a range with a single space.
    // The next replaces the same range with the autofilled content.
    if string == " " {
        self.rangeReplacedWithSpace = range
        self.rangeReplacedWithSpaceAt = Date()
    } else {
        if rangeReplacedWithSpace == range,
            let rangeReplacedWithSpaceAt = self.rangeReplacedWithSpaceAt,
            Date().timeIntervalSince(rangeReplacedWithSpaceAt) < 0.1 {

            DispatchQueue.main.async {
                // Whatever you use to move forward.
                self.moveForward()
            }
        }
        self.rangeReplacedWithSpace = nil
        self.rangeReplacedWithSpaceAt = nil
    }
}

答案 1 :(得分:1)

找到了解决方案。

使用密码管理器自动填充用户名和密码时,它将触发didBeginEditing两次,比人类以往任何时候都快。

因此,我计算了两次事件之间的时间。如果时间非常快,那么我假设使用了自动填充功能(例如FaceID或TouchID)来输入凭据并自动触发下一个UI,在我的情况下,用户点击“登录”。

很显然,您必须为要监视的UITextField设置正确的委派,但是一旦执行此操作:

var biometricAutofillTime: Date!

func textFieldDidBeginEditing(_ textField: UITextField) {
    if biometricAutofillTime != nil {
        if Date().timeIntervalSince(biometricAutofillTime) < 0.1 {
            // NOTE: Need to hesitate for a very short amount of time,
            //        because, otherwise, the second UITextField (password)
            //        won't yet be populated
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { self.didTapSignin() }
        }
        biometricAutofillTime = nil
    }
    biometricAutofillTime = Date()
}

答案 2 :(得分:0)

我认为没有更好的解决方案。

我注意到的一件事是自动填充仅在文本字段为空时启用。

因此,如果文本字段从空变为大于最小密码/用户名的长度,则很可能是自动填充/粘贴。

我正在使用shouldChangeCharactersIn来检测UITextField中的更改。我不确定是否存在在调用委托方法之前键盘中的文本可以一起批处理的情况。

答案 3 :(得分:0)

  

我想代表用户触发此操作。

如果这是您的主要目标,那么我在这里使用了一些不同的方法。

在显示登录表单后,我首先使用SecRequestSharedWebCredential检查iCloud钥匙串。如果封包返回凭据,则意味着用户打算使用该凭据登录,那么我将自动为其登录。否则,将登录文本设置为becomeFirstResponder()

这种方法不支持第三方密码管理器,但是我相信大多数人都使用iCloud钥匙串。

答案 4 :(得分:0)

我找到了另一种简单的方法。希望它能帮助正在寻找它的人。

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// Usually string is coming as single character when user hit the keyboard .. 
// but at AutoFill case it will come as whole string which recieved .. 
// at this moment you can replace what you currently have by what you have recieved.
// In below case I'm expecting to recieve 4 digits as OTP code .. you can change it by what you are expecting to recieve.
    if string.count == 4 {
            doWhatEverYouByAutoFillString(text: string)
            return true
        } 
    }
}

答案 5 :(得分:0)

这将检测用户何时通过密码自动填充。当用户从剪贴板粘贴文本时,它也可能触发。 (如果文本字段为空)

您可能可以通过此链接处理删除用户粘贴的案例的逻辑。 how to know when text is pasted into UITextView

  private var didAutofillTextfield: Bool = false {
    didSet {
      if didAutofillTextfield {
        // Fire analytics for user autofilling
      }
    }
  }


 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    // If the range is {0,0} and the string count > 1, then user copy paste text or used password autofill.
    didAutofillTextfield = range == NSRange(location: 0, length: 0) && string.count > 1
    return true
  }

答案 6 :(得分:0)

快捷键5:

每次用户在文本字段中键入内容时,都会触发以下委托方法。该字符串数通常为1,因此任何大于该数字的值都是自动填充或用户将某些文本粘贴到字段中。我仅在此密码字段上使用此委托。

extension LoginView: UITextFieldDelegate {

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if string.count > 1 {
            DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) { [weak self] in
                self?.endEditing(true)
            }
        }
        return true
    }
}

答案 7 :(得分:0)

我使用了这个委托方法:

func textFieldDidChangeSelection(_ textField: UITextField) {
    // call when user select something
}

来自文档:

<块引用>

方法 textFieldDidChangeSelection(_:) 当指定文本字段中的文本选择发生变化时通知代理。te