【问题标题】:How to detect when user used Password AutoFill on a UITextField如何检测用户何时在 UITextField 上使用密码自动填充
【发布时间】:2018-03-05 15:10:59
【问题描述】:

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

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

WWDC2017 密码自动填充会话说要使用 UITextFieldTextDidChange。这可行,但当然,当用户在这些字段中手动输入时也会触发。

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

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

【问题讨论】:

  • 我还想通过将使用情况添加到应用程序的分析中来了解用户是否真的使用密码自动填充。我们对 1Password 也是如此。
  • 这还不能解决吗?

标签: ios uitextfield autofill uitextfielddelegate


【解决方案1】:

不确定上一个答案是否在某个时候停止工作,但我无法让它工作 - 使用自动填充时我只收到一个 didBeginEditing 电话。

不过,我确实找到了检测自动填充的方法。请记住,可以在输入某些字符后使用自动填充,例如,如果用户已经在电话号码中输入了一些数字,那么他们会自动填充完整的号码。

对于 Swift 4/5:

private var fieldPossibleAutofillReplacementAt: Date?

private var fieldPossibleAutofillReplacementRange: 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
    // (or blank string starting with iOS 13.4).
    // The next replaces the same range with the autofilled content.
    if string == " " || string == "" {
        self.fieldPossibleAutofillReplacementRange = range
        self.fieldPossibleAutofillReplacementAt = Date()
    } else {
        if fieldPossibleAutofillReplacementRange == range, let replacedAt = self.fieldPossibleAutofillReplacementAt, Date().timeIntervalSince(replacedAt) < 0.1 {
            DispatchQueue.main.async {
                // Whatever you use to move forward.
                self.moveForward()
            }
        }
        self.fieldPossibleAutofillReplacementRange = nil
        self.fieldPossibleAutofillReplacementAt = nil
    }

    return true
}

【讨论】:

  • 函数根本不需要我。
  • 似乎在 iOS 13.4 上它使用空字符串 "" 而不是空格 " "
  • 谢谢,我已经更新了我的答案以涵盖空字符串行为。
【解决方案2】:

找到了解决办法。

当密码管理器用于自动填充用户名+密码时,它会触发两次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()
}

【讨论】:

    【解决方案3】:

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

    您可能可以使用此链接处理删除用户粘贴案例的逻辑.. 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
      }
    

    【讨论】:

      【解决方案4】:

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

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

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

      我正在使用shouldChangeCharactersIn 来检测 UITextField 的变化。我不确定是否存在在调用委托方法之前可以将来自键盘的文本批量处理的情况。

      【讨论】:

      • 这不再是真的了。自动完成确实需要一个空白字段,它会替换任何现有文本。
      【解决方案5】:

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

      如果这是您的主要目标,我将在这里采取一些不同的方法。

      在显示登录表单后,我首先使用SecRequestSharedWebCredential 检查 iCloud 钥匙串。如果闭包返回一个凭据,这意味着用户的意图是使用它登录,那么我会自动为他/她登录。否则,将登录文本设为becomeFirstResponder()

      这种方式不支持第三方密码管理器,但我相信大多数人都使用 iCloud Keychain。

      【讨论】:

        【解决方案6】:

        斯威夫特 5:

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

        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】:

          我使用了这个委托方法:

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

          来自文档:

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

          【讨论】:

            【解决方案8】:

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

            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
                    } 
                }
            }
            

            【讨论】:

            • 点击建议完成时,我收到一个空字符串(只是空格)。安全问题?
            • 您将在此空白之后收到正确的消息,所以此时不​​要做任何事情.. 尝试使用上述方法,请告诉我们它是否适合您。
            猜你喜欢
            • 1970-01-01
            • 2012-04-02
            • 1970-01-01
            • 2022-01-01
            • 2010-11-29
            • 2019-04-05
            • 2012-06-20
            • 2019-09-15
            • 2018-05-14
            相关资源
            最近更新 更多