web-dev-qa-db-de.com

iOS 11 Passwort deaktivieren AutoFill Zubehör Ansichtsoption?

Ab sofort möchte ich die neue Option, die iOS 11 bietet, deaktivieren, dh Passwörter in der App vorschlagen. Wenn ich die App unter iOS 11 starte, wird die Option zum automatischen Ausfüllen über der Tastatur angezeigt, und mein Textfeld für Benutzername und Kennwort wird nicht einmal angezeigt.

Meine Frage ist also, wie ich die neue Funktion zum automatischen Ausfüllen von Passwörtern deaktivieren kann, damit die Taste auf der Tastatur überhaupt nicht angezeigt wird und das allgemeine Verhalten dem vor iOS 11 entspricht.

enter image description here

67
zumzum

iOS 11 & 12 & 13 - Swift 4.2 & 5 (Aktualisiert):

        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 Erklärung:

Stellen Sie sicher, dass Sie alle Ihre UITextField Objekte so einrichten.

Wenn Sie zum Beispiel ein UITextField -Objekt haben, bei dem der Benutzer seine E-Mail-Adresse eingeben muss, und ein anderes, bei dem der Benutzer sein Kennwort eingeben muss, weisen Sie UITextContentType("") beiden ihrer textContentType -Eigenschaften zu . Andernfalls funktioniert es nicht und die AutoFill-Zubehöransicht wird weiterhin angezeigt.

57
Baran

iOS 12 scheint das Kennwort textFields auch an der Eigenschaft isSecureTextEntry und nicht nur an der Eigenschaft textContentType zu erkennen Das Verschwinden der Ansicht ist nur möglich, wenn Sie beide textContentType auf "nichts" setzen und die Funktion "secureEntry" entfernen (und eine Sicherheitslücke in Ihrer App verursachen), wodurch iOS 12 das Textfeld nicht als Kennwort "textField" erkennt und diese nervige Zusatzansicht anzeigt.

In meinem Fall verursachte das Zubehör einen Fehler, der dazu führte, dass meine App beim Tippen nicht mehr reagierte (was auch dazu führte, dass meine App im App-Überprüfungsprozess abgelehnt wurde). Also musste ich diese Funktion entfernen. Ich wollte dieses Sicherheitsmerkmal nicht aufgeben, also musste ich die Dinge selbst lösen.

Die Idee ist, die Funktion secureEntry zu entfernen, sie jedoch manuell hinzuzufügen. Es hat funktioniert:

enter image description here


Es kann so gemacht werden:

Swift 4 way:

Zuerst, wie hier beantwortet, setze textContentType auf nichts:

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

Dann deklarieren Sie eine String-Variable, die später unseren textField-Inhalt enthält:

var passwordValue = ""

Fügen Sie dem passwordTextField ein Ziel hinzu, das bei jeder Änderung des textField-Inhalts aufgerufen wird:

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

Nun, das ist es, was die Magie bewirkt. Deklarieren Sie die Funktion, die die Textersetzungen handhabt:

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

Setzen Sie schließlich textFields autocorrectionType auf .no, um Text mit automatischer Worterkennung zu entfernen:

passwordText.autocorrectionType = .no

Verwenden Sie passwordValue, um die Anmeldung durchzuführen.

Hoffe, es wird jemandem helfen.

[~ # ~] Update [~ # ~]

Es werden auch eingefügte Werte abgefangen, die zuvor nicht hinzugefügt wurden.

10
Gal Shahar

Sie können die Erweiterung für UITextContentType wie folgt hinzufügen

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

danach können Sie es verwenden

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

Die Funktion kann deaktiviert werden, indem ein Inhaltstyp angegeben wird, der weder Benutzername noch Kennwort enthält. Wenn der Benutzer beispielsweise eine E-Mail-Adresse eingeben soll, können Sie diese verwenden

usernameTextField?.textContentType = .emailAddress
8
gebirgsbärbel

Ein sehr einfacher Ansatz in ios11 hat für mich funktioniert. Angenommen, Ihre iboutlets sind usernametextfield und passwordtextfield. Verwenden Sie in der Funktion viewDidLoad () Ihres Viewcontrollers, der die beiden Outlest enthält, den folgenden Code

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

Danach wird die Option zum automatischen Ausfüllen nicht mehr angezeigt, wenn Sie auf Ihre Textfelder tippen.

6
Ammad

Ziel-C

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

Das hat bei mir funktioniert.

5

Das automatische Ausfüllen ist standardmäßig für Benutzer aktiviert. iOS speichert alle Passwörter im Schlüsselbund und stellt sie über die Tastatur in Ihren Apps zur Verfügung. UITextView und UITextField werden beim automatischen Ausfüllen des Kennworts automatisch berücksichtigt. Sie können die Funktion deaktivieren, indem Sie einen Inhaltstyp angeben, der weder Benutzername noch Kennwort ist. Wenn die Inhaltstypinformationen jedoch bereits im Schlüsselbund gespeichert sind, werden sie in der Schnellleiste angezeigt. Es ist daher besser, einen leeren UITextContentType -Typ zuzuweisen, und es wird keine Quickbar angezeigt.

Beispiel:

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

Dies funktionierte für iOS 12 und 10:

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

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

Ziel C-Version:

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

woher

#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)
2
wzbozon

als Antwort auf @Gal Shahar Antwort.

iOS 12 Kennwort textFields anhand der Eigenschaft isSecureTextEntry und nicht nur anhand der Eigenschaft textContentType erkennen.

Umgehung des Vorschlags zum automatischen Ausfüllen.

  1. setzen Sie die Eigenschaft isSecureTextEntry auf false.

self.passwordTextField.secureTextEntry = NO;

  1. Fügen Sie eine UITextField-Delegatmethode hinzu und aktivieren Sie die Eigenschaft isSecureTextEntry.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    if (textField == self.passwordTextField && !self.passwordTextField.secureTextEntry) {
        self.passwordTextField.secureTextEntry = YES;
    }

    return YES;
}

HINWEIS: - Do NOT Verwenden Sie die shouldBeginEditing UITextField-Delegatmethode. Es wird weiterhin ein Vorschlag zum automatischen Ausfüllen angezeigt. Do NOT Use textFieldDidChange UITextField delegate method Löscht den ersten Zeichner automatisch, so wie es geschieht, nachdem der erste Zeichner angezeigt wird. Und 'secureTextEntry' wird das Feld leeren.

1
ashish
self.passwordTextField.autocorrectionType = NO;

Es scheint nicht zu funktionieren, das Schlüsselbundschild ist noch da,

self.passwordTextField.textContentType = UITextContentTypeName;

Der obige Code funktioniert, aber wenn die Benutzer ihr Apple ID-Konto eingerichtet haben, wird der Name der Apple id auf der Tastatur angezeigt Ich kann es nicht deaktivieren, indem ich autocorrectionType auf Nein setze. Ich bin mir nicht sicher, ob Apple diese Funktion zum automatischen Ausfüllen noch verfeinert. Es ist im Moment ziemlich fehlerhaft.

1
Roger Han

Sie können die Benutzer-/Kennwort-Kombinationserkennung "ausschalten", indem Sie dem Kennworttextfeld einen Platzhalter textContentType zuweisen.

passwordFormField.textContentType = UITextContentType("dummy")

Dadurch wurde das Schlüsselsymbol sowohl für das Kennwortfeld als auch für das vorangegangene E-Mail-Feld deaktiviert. Auf diese Weise verwenden Sie keinen der vordefinierten Werte und vermeiden, dass in der Zubehöransicht der Tastatur Vorschläge ohne Bezug angezeigt werden.

1
Miguel Cabeça

Sie könnten hier verschiedene Antworten versuchen, die darauf schließen, dass es wahrscheinlich möglich ist, die Zubehöransicht zu entfernen. Dies hinterlässt jedoch einige Fehler.

Wie Sie inputAccessoryView ausblenden, ohne die Tastatur zu schließen

Sie könnten versuchen, eine benutzerdefinierte Tastatur nur für Kennwortfelder zu implementieren. Versuchen Sie auch, Vorschläge für Ihr Textfeld zu deaktivieren, ich denke, dass auch die Zubehöransicht verbirgt.

BEARBEITEN: Keine Antwort auf Apple Foren zu derselben Frage wie bisher. Außerdem konnte ich in der offiziellen uitextfield-Dokumentation nichts dazu finden.

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

1
Rishabh

Soweit ich weiß, funktioniert Bems Antwort in iOS 12 nicht und Gal Shahars Antwort berücksichtigt einige Edge-Fälle nicht (zum Beispiel, wenn ein Benutzer mehrere Zeichen gleichzeitig löscht). Ich habe das mit einer IBAction umgangen, sodass ich nicht mehr nach iOS-Versionen suchen muss. Ich bin nur ein Anfänger, daher ist dies möglicherweise nicht die "beste" oder effizienteste Antwort, aber es ergab für mich den größten Sinn:

Deaktivieren Sie zuerst "Secure Text Entry" im Storyboard oder setzen Sie es per Code für Ihr Passwort UITextField auf "false"/"NO". Dadurch wird verhindert, dass iOS versucht, das automatische Ausfüllen durchzuführen.

Verknüpfen Sie dann Ihr Passwort UITextField mit einer IBAction. Meins heißt auf:

  • Die Bearbeitung hat begonnen
  • Die Bearbeitung hat sich geändert
  • Die Bearbeitung wurde beendet

Die von mir geschriebene IBAction-Funktion ermittelt die Unterschiede zwischen dem Startkennwort eines Benutzers und der Eingabe in das Kennwort UITextField und erstellt anhand dieser Informationen ein neues Kennwort:

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

Konstruktive Kritik ist erwünscht!

1
Escargot

Ich denke, setzen Sie alle UITextField TextContentType in Form auf UITextContentType("") oder .oneTimeCode ist keine saubere Lösung. Aktivieren/Deaktivieren von isSecureTextEntry gibt Ihnen immer noch das gleiche Problem.

@Gal Shahars Antwort ist nett, aber es ist immer noch nicht perfekt. Das maskierte Zeichen ist nicht dasselbe wie das maskierte Zeichen, das im sicheren Eingabetext von Apple verwendet wird. Es sollte das Unicode-Zeichen 'BLACK CIRCLE' (U + 25CF) https://www.fileformat.info/info/unicode/char/25cf/index.htm verwenden

Es behandelt auch keine Cursorbewegung. Durch das Einfügen von Text in der Mitte wird die Cursorposition an das Ende des Texts verschoben. Sie erhalten den falschen Wert, wenn Sie Text auswählen und ersetzen.

Wenn Sie sich für die Verwendung der benutzerdefinierten Funktion isSecureEntryText entscheiden, um das automatische Ausfüllen des Kennworts zu vermeiden, finden Sie hier den Code:

Swift 5 (einfache 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 (KOMPLETTE Version mit Sicherung der letzten 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
Sandy Akbar