Подтвердить что ты не робот

IOS 11 отключить функцию просмотра автозаполнения пароля?

На данный момент я хотел бы отказаться от новой опции, предлагаемой iOS 11, то есть предложить пароли в приложении. Когда я запускаю приложение на iOS 11, я получаю опцию автозаполнения поверх клавиатуры, а текстовое поле с именем пользователя и паролем даже не отображается.

Итак, мой вопрос: как отключить функцию автозаполнения нового пароля, так что клавиша на клавиатуре вообще не отображается, а общее поведение такое же, как и pre iOS 11?

введите описание изображения здесь

4b9b3361

Ответ 1

iOS 11 & 12 & 13 - Swift 4.2 & 5 (обновлено):

        if #available(iOS 12, *) {
            // iOS 12 & 13: Not the best solution, but it works.
            passwordTextField.textContentType = .oneTimeCode
        } else {
            // iOS 11: Disables the autofill accessory view. 
            // For more information see the explanation below.
            emailTextField.textContentType = .init(rawValue: "")
            passwordTextField.textContentType = .init(rawValue: "")
        }

Объяснение iOS 11:

Убедитесь, что вы настроили все свои объекты UITextField следующим образом.

Если у вас есть, например, объект UITextField, в котором пользователь должен ввести свой адрес электронной почты, а другой объект, в котором пользователь должен ввести свой пароль, назначьте UITextContentType("") обоим их свойствам textContentType. В противном случае он не будет работать, а вспомогательный вид автозаполнения будет по-прежнему отображаться.

Ответ 2

iOS 12, кажется, распознает textFields пароля также по свойству isSecureTextEntry а не только по свойству textContentType, поэтому заставить этот вспомогательный вид исчезнуть на самом деле невозможно, если вы оба не установите textContentType в ничто и не удалите функцию secureEntry (и не вызовете уязвимость в вашем приложении), который затем не позволяет iOS 12 распознать textField в качестве пароля textField и показать это надоедливое вспомогательное представление.

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

Идея состоит в том, чтобы удалить функцию secureEntry, но добавить ее вручную. Это сработало:

enter image description here


Это можно сделать так:

Свифт 4 пути:

Во-первых, как ответили здесь, установите textContentType в ничего:

if #available(iOS 10.0, *) {
    passwordText.textContentType = UITextContentType("")
    emailText.textContentType = UITextContentType("")
}

Затем объявите переменную String, которая позже будет содержать реальный контент textField:

var passwordValue = ""

Добавьте цель в passwordTextField, который будет вызываться при каждом изменении содержимого textField:

passwordText.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)

Теперь, что будет делать магию, объявите функцию, которая будет обрабатывать замены текста:

@objc func textFieldDidChange(_ textField: UITextField) {
    if textField.text!.count > 1 {
        // User did copy & paste
        if passwordValue.count == 0 { // Pasted into an empty textField
            passwordValue = String(textField.text!)
        } else { // Pasted to a non empty textField
            passwordValue += textField.text!.substring(from: passwordValue.count)
        }
    } else {
        // User did input by keypad
        if textField.text!.count > passwordValue.count { // Added chars
            passwordValue += String(textField.text!.last!)
        } else if textField.text!.count < passwordValue.count { // Removed chars
            passwordValue = String(passwordValue.dropLast())
        }
    }
    self.passwordText.text = String(repeating: "•", count: self.passwordText.text!.count)
}

Наконец, установите TextField autocorrectionType в .no для удаления интеллектуального ввода текста:

passwordText.autocorrectionType = .no

Для этого используйте passwordValue для входа в систему.

Надеюсь, это кому-нибудь поможет.

ОБНОВИТЬ

Он также ловит вставленные значения, забыл добавить его раньше.

Ответ 3

Эта функция может быть отключена, указав тип контента, который не является ни именем пользователя, ни паролем. Например, если пользователь должен ввести адрес электронной почты, вы можете использовать

usernameTextField?.textContentType = .emailAddress

Ответ 4

Вы можете добавить расширение для UITextContentType, например,

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

после этого вы можете использовать его

if #available(iOS 10.0, *) {
    passwordField.textContentType = .unspecified
}

Ответ 5

Очень простой подход в ios11 работал у меня. Предположим, что ваши iboutlets - это usernametextfield и passwordtextfield. В функции viewDidLoad() вашего диспетчера view, которая содержит оба значения, используйте следующий код

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

После этого вы не увидите опцию автозаполнения при нажатии на текстовые поля.

Ответ 6

Objective-C

if (@available(iOS 10, *)){
    self.tfEmail.textContentType = @"";
    self.tfPassword.textContentType = @"";
}

Это сработало для меня.

Ответ 7

Автозаполнение по умолчанию включено для пользователей. iOS сохраняет все пароли в цепочке ключей и делает их доступными на клавиатуре в ваших приложениях. UITextView и UITextField автоматически учитываются для пароля автозаполнения. вы можете отключить, указав тип контента, который не является ни именем пользователя, ни паролем, но если информация о типе содержимого, уже сохраненная в цепочке ключей, будет отображаться на панели быстрого доступа. поэтому лучше назначить пустой тип UITextContentType, и он не будет показывать панель быстрого доступа.

Пример:

  if #available(iOS 10.0, *) {
  self.textField.textContentType = UITextContentType("")
  } else {
  // Fallback on earlier versions
 }

Ответ 8

Это работало для ios 12 и 10:

if (@available(iOS 10, *)) {
    passwordTextField.textContentType = UITextContentTypeStreetAddressLine2;
}

if (@available(iOS 12, *)) {
    passwordTextField.textContentType = UITextContentTypeOneTimeCode;
}

Ответ 9

Объективная версия C:

if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
    self.passwordTextField.textContentType = @"";
    self.confirmPasswordTextField.textContentType = @"";
}

где

#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)

Ответ 10

Здесь вы можете попробовать разные ответы, которые заключают, что можно удалить аксессуар. Но это оставляет некоторые ошибки.

Как скрыть inputAccessoryView без отклонения клавиатуры

Вы могли бы попытаться реализовать пользовательскую клавиатуру, возможно, только для полей пароля. Также попробуйте отключить предложения для вашего текстового поля, я думаю, что также скрывает аксессуар.

EDIT: На вопрос о яблочных форумах на тот же вопрос пока нет ответа. Также я не мог найти ничего об этом в официальной документации uitextfield.

https://forums.developer.apple.com/thread/82442

Ответ 11

self.passwordTextField.autocorrectionType = NO;

Кажется, он не работает, знак цепочки для ключей все еще там,

self.passwordTextField.textContentType = UITextContentTypeName;

Приведенный выше код работает, но если пользователи настроили свою учетную запись Apple ID, тогда имя идентификатора яблока будет отображаться на клавиатуре, его нельзя отключить, установив для autocorrectionType значение Нет, не уверен, что Apple по-прежнему улучшает эту функцию автозаполнения щас глючит прямо сейчас.

Ответ 12

Вы можете "отключить" обнаружение комманды имени пользователя/пароля, назначив фиктивный текст textContentType в текстовое поле пароля.

passwordFormField.textContentType = UITextContentType("dummy")

Это отключило символ клавиши как для поля пароля, так и для поля электронной почты, которое ему предшествовало, и таким образом вы не используете одно из предопределенных значений и избегаете отображения несвязанных предложений в представлении аксессуаров клавиатуры.

Ответ 13

в ответ на @Gal Shahar Ответ.

iOS 12 распознает текстовые isSecureTextEntry пароля по свойству isSecureTextEntry а не только по свойству textContentType.

Способ обойти предложение автозаполнения.

  1. установите isSecureTextEntry свойства isSecureTextEntry значение false.

self.passwordTextField.secureTextEntry = NO;

  1. Добавьте метод делегата UITextField и включите свойство isSecureTextEntry.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    if (textField == self.passwordTextField && !self.passwordTextField.secureTextEntry) {
        self.passwordTextField.secureTextEntry = YES;
    }

    return YES;
}

ПРИМЕЧАНИЕ. - НЕ shouldBeginEditing метод делегата shouldBeginEditing UITextField, в котором по-прежнему будет отображаться предложение автозаполнения. НЕ textFieldDidChange метод делегата textFieldDidChange UITextField. Он автоматически удалит первый символ, поскольку это произойдет после отображения первого символа. И "secureTextEntry" очистит поле.

Ответ 14

Из того, что я могу сказать, ответ Bem не работает в iOS 12, а ответ Gal Shahar не учитывает некоторые крайние случаи (например, если пользователь удаляет сразу несколько символов). Я работал над этим, используя IBAction, таким образом устраняя необходимость проверять версию iOS в целом. Я просто новичок, так что это может быть не самый лучший или самый эффективный ответ, но для меня это было наиболее логично:

Сначала снимите флажок "Безопасный ввод текста" в раскадровке или установите для него значение "ложь"/"НЕТ" с помощью кода для вашего пароля UITextField. Это предотвратит попытку автозаполнения iOS.

Затем свяжите ваш пароль UITextField с IBAction. Шахта называется на:

  • Редактирование началось
  • Редактирование изменилось
  • Редактирование закончилось

Написанная мной функция IBAction определяет различия между начальным паролем пользователя и тем, что было введено в пароль UITextField, и создает новый пароль на основе этой информации:

class Login: UIViewController {
    var password = ""

    override func viewDidLoad() { super.viewDidLoad() }

    @IBAction func editPasswordField(_ sender: UITextField) {
        var input = Array(sender.text ?? "")
        var oldPassword = Array(password)
        var newPassword = Array("")

        //if character(s) are simply deleted from "passwordField" (not replaced or added to), "cursorPosition" is used to determine which corresponding character(s) need to also be removed from "oldPassword"
        //this is indicated by "input" comprising of only "•" (bullets) and being shorter in length than "oldPassword"
        var onlyBullets = true
        for char in input { if char != "•" { onlyBullets = false } }
        if onlyBullets && input.count < oldPassword.count {
            if let selectedRange = sender.selectedTextRange {
                let cursorPosition = sender.offset(from: sender.beginningOfDocument, to: selectedRange.start)
                let prefix = String(oldPassword.prefix(cursorPosition))
                let suffix = String(oldPassword.suffix(input.count - cursorPosition))
                input = Array(prefix + suffix)
            } else { input = Array("") }
        }

        //if no changes were made via input, input would comprise solely of a number of bullets equal to the length of "oldPassword"
        //therefore, the number of changes made to "oldPassword" via "input" can be measured with "bulletDifference" by calculating the number of characters in "input" that are NOT bullets
        var bulletDifference = oldPassword.count
        for char in input { if char == "•" { bulletDifference -= 1 } }

        //the only way "bulletDifference" can be less than 0 is if a user copy-pasted a bullet into "input", which cannot be allowed because it breaks this function
        //if a user pastes bullet(s) into "input", "input" is deleted
        //an edge case not accounted for is pasting a mix of characters and bullets (i.e. "ex•mple") when "oldPassword.count" exceeds the number of bullets in the mixed input, but this does not cause crashes and therefore is not worth preventing
        if bulletDifference < 0 {
            bulletDifference = oldPassword.count
            input = Array("")
        }

        //"bulletDifference" is used to remove every character from "oldPassword" that corresponds with a character in "input" that has been changed
        //a changed character in "input" is indicated by the fact that it is not a bullet
        //once "bulletDifference" equals the number of bullets deleted, this loop ends
        var bulletsDeleted = 0
        for i in 0..<input.count {
            if bulletsDeleted == bulletDifference { break }
            if input[i] != "•" {
                oldPassword.remove(at: i - bulletsDeleted)
                bulletsDeleted += 1
            }
        }

        //what remains of "oldPassword" is used to substitute bullets in "input" for appropriate characters to create "newPassword"
        //for example, if "oldPassword" is "AcbDE" and "input" is "•bc••", then "oldPassword" will get truncated to "ADE" and "newPassword" will equal "A" + "bc" + "DE", or "AbcDE"
        var i = 0
        for char in input {
            if char == "•" {
                newPassword.append(oldPassword[i])
                i += 1
            } else { newPassword.append(char) }
        }
        password = String(newPassword)

        //"passwordField.text" is then converted into a string of bullets equal to the length of the new password to ensure password security in the UI
        sender.text = String(repeating: "•", count: password.count)
    }
}

Конструктивная критика приветствуется!

Ответ 15

Я думаю, установить все UITextField textContentType в форме UITextContentType("") или .oneTimeCode не является чистым решением. Включение/отключение isSecureTextEntry прежнему isSecureTextEntry ту же проблему.

@Gal Shahar Ответ хорош, но все еще не совершенен. Маскированный символ не совпадает с маскированным символом, который используется в защищенном тексте ввода от apple. Следует использовать символ Unicode 'BLACK CIRCLE' (U + 25CF) https://www.fileformat.info/info/unicode/char/25cf/index.htm

Кроме того, он не обрабатывает движение курсора. Это изменит позицию курсора в конец текста при вставке текста в середине. Это даст вам неправильное значение при выборе и замене текста.

Когда вы решите использовать пользовательский isSecureEntryText, чтобы избежать автозаполнения пароля, вот код:

Swift 5 (простая версия)

@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 (полная версия с сохранением последней анимации персонажа)

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

Ответ 16

Это сработало для меня:

ПРИМЕЧАНИЕ: попробуйте ввести этот код в пароль, подтверждение пароля (если применимо) и текстовые поля электронной почты. Я не помещал это в текстовое поле электронной почты, и оно все еще появлялось для двух полей пароля.

if #available(iOS 12, *) {
     // iOS 12: Not the best solution, but it works.
     cell.textField.textContentType = .oneTimeCode
} else {
     // iOS 11: Disables the autofill accessory view.
     cell.textField.textContentType = .init(rawValue: "")
}