iOS 11 disable password autofill accessory view option?

后端 未结 20 2322
孤独总比滥情好
孤独总比滥情好 2020-11-28 04:20

As of now I would like to opt out of the new option iOS 11 gives, that is to suggest passwords in the app. When I run the app on iOS 11 I get the autofill option on top of t

相关标签:
20条回答
  • 2020-11-28 04:36

    I think set all UITextField textContentType in form to UITextContentType("") or .oneTimeCode is not a clean solution. Enable/Disable isSecureTextEntry still give you the same issue.

    @Gal Shahar 's Answer is nice but it is still not perfect. The masked char is not the same as the masked char that used in secure entry text from apple. It should use Unicode Character 'BLACK CIRCLE' (U+25CF) https://www.fileformat.info/info/unicode/char/25cf/index.htm

    Also, it is not handling cursor movement. It will change the cursor position to the end of the text when inserting text in the middle. It will give you the wrong value when selecting and replacing text.

    When you decide to use custom isSecureEntryText to avoid autofill password, here is the code:

    Swift 5 (simple version)

    @IBOutlet weak var passwordTextField: UITextField!
    
    var maskedPasswordChar: String = "●"
    var passwordText: String = ""
    var isSecureTextEntry: Bool = true {
        didSet {
            let selectedTextRange = passwordTextField.selectedTextRange
            passwordTextField.text = isSecureTextEntry ? String(repeating: maskedPasswordChar, count: passwordText.count) : passwordText
            passwordTextField.selectedTextRange = selectedTextRange
        }
    }
    
    //this is UITextFieldDelegate
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    
        if textField == passwordTextField {
            //update password string
            if let swiftRange = Range(range, in: passwordText) {
                passwordText = passwordText.replacingCharacters(in: swiftRange, with: string)
            } else {
                passwordText = string
            }
    
            //replace textField text with masked password char
            textField.text =  isSecureTextEntry ? String(repeating: maskedPasswordChar, count: passwordText.count) : passwordText
    
            //handle cursor movement
            if let newPosition = textField.position(from: textField.beginningOfDocument, offset: range.location + string.utf16.count) {
                textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
            }
            return false
        }
        return true
    }
    

    Swift 5 (COMPLETE version with securing last char animation)

    private struct Constants {
        static let SecuringLastCharPasswordDelay = 1.5
    }
    
    @IBOutlet weak var passwordTextField: UITextField!
    
    private var secureTextAnimationQueue: [String] = []
    
    var maskedPasswordChar: String = "●"
    var passwordText: String = ""
    var isSecureTextEntry: Bool = true {
        didSet {
            secureTextAnimationQueue.removeAll()
            let selectedTextRange = passwordTextField.selectedTextRange
            passwordTextField.text = isSecureTextEntry ? String(repeating: maskedPasswordChar, count: passwordText.count) : passwordText
            passwordTextField.selectedTextRange = selectedTextRange
        }
    }
    
    //this is UITextFieldDelegate
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    
        if textField == passwordTextField {
            //update password string
            if let swiftRange = Range(range, in: passwordText) {
                passwordText = passwordText.replacingCharacters(in: swiftRange, with: string)
            } else {
                passwordText = string
            }
    
            //replace textField text with masked password char
            updateTextFieldString(textField, shouldChangeCharactersIn: range, replacementString: string)
    
            //handle cursor movement
            if let newPosition = textField.position(from: textField.beginningOfDocument, offset: range.location + string.utf16.count) {
                textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
            }
            return false
        }
        return true
    }
    
    private func updateTextFieldString(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) {
        if isSecureTextEntry {
            if string.count == .one, let text = textField.text {
                let maskedText = String(repeating: maskedPasswordChar, count: text.count)
    
                var newMaskedText = String()
                if let swiftRange = Range(range, in: maskedText) {
                    newMaskedText = maskedText.replacingCharacters(in: swiftRange, with: string)
                } else {
                    newMaskedText = text + maskedText
                }
    
                textField.text = newMaskedText
                secureTextAnimationQueue.append(string)
                asyncWorker.asyncAfter(deadline: .now() + Constants.SecuringLastCharPasswordDelay) { [weak self] in
                    self?.securingLastPasswordChar()
                }
            } else {
                secureTextAnimationQueue.removeAll()
                textField.text = String(repeating: maskedPasswordChar, count: passwordText.count)
            }
        } else {
            textField.text = passwordText
        }
    }
    
    private func securingLastPasswordChar() {
        guard secureTextAnimationQueue.count > .zero, isSecureTextEntry else { return }
        secureTextAnimationQueue.removeFirst()
        if secureTextAnimationQueue.count == .zero {
            let selectedTextRange = passwordTextField.selectedTextRange
            passwordTextField.text = String(repeating: maskedPasswordChar, count: passwordText.count)
            passwordTextField.selectedTextRange = selectedTextRange
        }
    }
    
    0 讨论(0)
  • 2020-11-28 04:37

    You can add extension for UITextContentType like this

    extension UITextContentType {
        public static let unspecified = UITextContentType("unspecified")
    }
    

    after that, you can use it

    if #available(iOS 10.0, *) {
        passwordField.textContentType = .unspecified
    }
    
    0 讨论(0)
  • 2020-11-28 04:38

    A very simple approach in ios11 worked for me. Suppose your iboutlets are usernametextfield and passwordtextfield. In viewDidLoad() function of your viewcontroller that holds the both outlest use the following code

    usernametextfield.textContentType = UITextContentType("")
    passwordtextfield.textContentType = UITextContentType("")
    

    After this you wont see autofill accessory option when you tap on your textfields.

    0 讨论(0)
  • 2020-11-28 04:40

    The feature can be disabled by specifying a content type that is neither username nor password. For example, if the user should enter an email address, you could use

    usernameTextField?.textContentType = .emailAddress
    
    0 讨论(0)
  • 2020-11-28 04:41

    Crazy staff happening in this topic. I've made without iOS proposing me a password, but given me an autofill for email only. Just if someone need it so. After different combinations and different type of textContentType I've made it as I wanted.

    1. Email Text field with iOS autofill proposing be something.
    2. Password text field with no iOS system proposing me a new password, but filling it with password if I choose it from email text field.
    3. Password text field to have secure entry text.

    And with this code it worked. Doesn't matter if you have email or username it will make you a proposition with what you need. So I've disabled accessory autofill view and left only autofill in toolbar of keyboard.

    self.passwordField.isSecureTextEntry = true
    
    if #available(iOS 11.0, *) {
        self.emailField.textContentType = .username
        self.emailField.keyboardType = .emailAddress
    }
    
    if #available(iOS 12.0, *) {
        self.passwordField.textContentType = .password
        self.passwordField.keyboardType = .default
    }
    
    0 讨论(0)
  • 2020-11-28 04:44

    I have attached the screenshot. you can change the content Type as Username in the storyboard or you can do programatically. you may create an extension for UITextfield .

    func diableAutofill() {
            self.autocorrectionType = .no
            if #available(iOS 11.0, *) {
                self.textContentType = .username
            } else {
                self.textContentType = .init("")
            }
        }
    
    0 讨论(0)
提交回复
热议问题