今のところ、iOS 11が提供する新しいオプション、つまりアプリでパスワードを提案することをオプトアウトしたいと思います。iOS 11でアプリを実行すると、キーボードの上部に自動入力オプションが表示され、ユーザー名とパスワードのテキストフィールドも表示されません。
だから、私の質問は、キーボードのキーがまったく表示されず、全体的な動作がiOS 11以前と同じになるように、新しいパスワードの自動入力機能を一度に無効にするにはどうすればよいですか?
回答:
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プロパティにます。それ以外の場合は機能せず、autoFillアクセサリビューが引き続き表示されます。
UITextContentTypeものが導入されていますnewPassword (developer.apple.com/documentation/uikit/uitextcontenttype/…を参照)。パスワードテキストフィールドのコンテンツタイプをこのタイプに設定してみてください。ユーザーは新しいパスワードを設定する必要があり、自動入力アクセサリビューを使用して以前に設定したパスワードを使用/アクセスしないため、iOSは自動入力アクセサリビューを表示しないと思います。今のところ、これは理論にすぎません。これが機能するかどうかはわかりませんが、機能するかどうかをお知らせください。
UITextContentType しnewPasswordても機能しません。@GalShaharのソリューションを試しましたが、気に入らなかった。代わりに、UITextContentTypeをに設定していoneTimeCode ます。それは今のところうまくいきます。
isSecureTextEntryするだけでなく、最初にfalseに設定UITextContentTypeする必要がありましたoneTimeCode。isSecureTextEntry彼らがテキストフィールドを入力し始めたら、私たちは好きなように設定することができます。
.isSecureTextEntryするtrue前にに設定textContentTypeし.oneTimeCodeており、期待どおりに機能します。コードがどのように見えるかはわかりませんが、テキストフィールドを初期化するときは、プロパティを設定する順序は重要ではありません。
iOS 12は、パスワードtextFieldsを、isSecureTextEntryプロパティだけでなくプロパティによっても認識しているようです。textContentType。そのため、textContentTypeをnoに設定し、secureEntry機能を削除しない限り(アプリにセキュリティ上の欠陥が発生しない限り)、このアクセサリビューを非表示にすることは実際には不可能です。次に、iOS 12がtextFieldをパスワードtextFieldとして認識し、この迷惑なアクセサリビューを表示しないようにします。
私の場合、アクセサリが原因でバグが発生し、タップするとアプリが応答しなくなりました(これにより、アプリのレビュープロセスでアプリが拒否されました)。そのため、この機能を削除する必要がありました。このセキュリティ機能をあきらめたくなかったので、自分で解決しなければなりませんでした。
アイデアは、secureEntry機能を削除することですが、手動で追加します。それはうまくいきました:
それは次のように行うことができます:
Swift 4ウェイ:
まず、ここで答えたように、textContentType何も設定しません。
if #available(iOS 10.0, *) {
passwordText.textContentType = UITextContentType("")
emailText.textContentType = UITextContentType("")
}
それよりも、後でtextFieldの実際のコンテンツを含むString変数を宣言します。
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)
}
最後に、設定テキストフィールドのautocorrectionTypeと.no予測テキストを削除するには:
passwordText.autocorrectionType = .no
それだけです、使用してください passwordValueです。ログインを実行するします。
それが誰かを助けることを願っています。
更新
貼り付けられた値もキャッチし、前に追加するのを忘れていました。
この機能は、ユーザー名でもパスワードでもないコンテンツタイプを指定することで無効にできます。たとえば、ユーザーがメールアドレスを入力する必要がある場合は、次のように使用できます。
usernameTextField?.textContentType = .emailAddress
@Gal ShaharAnswerへの返信。
iOS 12は、isSecureTextEntryプロパティだけでなくプロパティによってパスワードtextFieldsを認識しますtextContentType。
自動入力の提案をバイパスする方法。
isSecureTextEntry プロパティをfalseに設定します。self.passwordTextField.secureTextEntry = NO;
isSecureTextEntry プロパティを有効にします。- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (textField == self.passwordTextField && !self.passwordTextField.secureTextEntry) {
self.passwordTextField.secureTextEntry = YES;
}
return YES;
}
注:-UITextFieldデリゲートメソッドは使用しないでくださいshouldBeginEditing。自動入力の提案が表示されます。UITextFieldデリゲートメソッドは使用しないでくださいtextFieldDidChange。最初の文字が表示された後に発生するため、最初の文字は自動的に削除されます。また、「secureTextEntry」はフィールドを空にします。
ios11の非常に単純なアプローチが私のために働いた。iboutletがusernametextfieldとpasswordtextfieldであるとします。両方を保持するviewcontrollerのviewDidLoad()関数で、次のコードを使用します
usernametextfield.textContentType = UITextContentType("")
passwordtextfield.textContentType = UITextContentType("")
この後、テキストフィールドをタップしても自動入力アクセサリオプションは表示されません。
自動入力は、デフォルトでユーザーに対して有効になっています。iOSはすべてのパスワードをキーチェーンに保存し、アプリのキーボードで使用できるようにします。UITextViewそして、UITextField自動的にオートフィルパスワードを入力すると考えます。ユーザー名でもパスワードでもないコンテンツタイプを指定することで無効にできますが、コンテンツタイプ情報がすでにキーチェーンに保存されている場合は、クイックバーに表示されます。空のUITextContentTypeタイプを割り当てる方がよいので、クイックバーは表示されません。
例:
if #available(iOS 10.0, *) {
self.textField.textContentType = UITextContentType("")
} else {
// Fallback on earlier versions
}
textContentTypeパスワードテキストフィールドにダミーを割り当てることにより、ユーザー名/パスワードの組み合わせ検出を「オフ」にすることができます。
passwordFormField.textContentType = UITextContentType("dummy")
これにより、パスワードフィールドとその前の電子メールフィールドの両方のキー記号がオフになりました。このようにして、事前定義された値の1つを使用せず、キーボードアクセサリビューに無関係な提案が表示されないようにします。
newPassword12UITextContentTypeのタグを付けています 。ただし、この新しい動作を回避する方法はわかりません。
Objective 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)
ここでさまざまな回答を試して、アクセサリビューを削除できる可能性が高いと結論付けることができます。しかし、これにはいくつかのバグが残ります。
パスワードフィールドに対してのみ、カスタムキーボードの実装を試みることができます。また、テキストフィールドの提案を無効にしてみてくださいaccessoryView。これも。を非表示にすると思います。
編集:同じ質問に関するAppleフォーラムにはまだ回答がありません。また、公式UITextFieldドキュメントではこれに関することは何も見つかりませんでした。
このトピックで起こっているクレイジーなスタッフ。iOSでパスワードを提案せずに作成しましたが、メールのみの自動入力を受け取りました。誰かがそれを必要とする場合にのみ。さまざまな組み合わせとさまざまなタイプの後で、textContentType私は思い通りにそれを作りました。
そして、このコードでそれは機能しました。あなたが持っているemailかどうかは関係ありません、またはusernameそれはあなたがあなたが必要とするものであなたに提案をするでしょう。そのため、アクセサリの自動入力ビューを無効にし、キーボードのツールバーに自動入力のみを残しました。
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
}
私の知る限り、Bemの答えはiOS 12では機能せず、Gal Shaharの答えはいくつかのエッジケースを考慮していません(たとえば、ユーザーが一度に複数の文字を削除した場合)。私はIBActionを使用してこれを回避したので、iOSのバージョンを完全にチェックする必要がなくなりました。私は初心者なので、これは「最良の」答えでも最も効率的でもないかもしれませんが、私にとって最も理にかなっています。
まず、ストーリーボードの「セキュアテキストエントリ」のチェックを外すか、パスワードUITextFieldのコードを使用して「false」/「NO」に設定します。これにより、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)
}
}
建設的な批判は大歓迎です!
self.passwordTextField.autocorrectionType = NO;
それは機能していないようです、キーチェーンサインはまだそこにあります、
self.passwordTextField.textContentType = UITextContentTypeName;
上記のコードは機能しますが、ユーザーがApple IDアカウントを設定した場合、Apple IDの名前がキーボードに表示され、autocorrectionTypeをNoに設定して無効にすることはできません。Appleがこの自動入力機能を引き続き改良するかどうかはわかりません。 、今はかなりバグがあります。
これは私のために働いた:
注:このコードをパスワード、パスワード確認(該当する場合)、および電子メールテキストフィールドに入力してみてください。私はそれを電子メールのテキストフィールドに配置していませんでしたが、それでも2つのパスワードフィールドにポップアップしていました。
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: "")
}
フォーム内のすべてのUITextFieldtextContentTypeをに設定するUITextContentType("")か.oneTimeCode、クリーンなソリューションではないと思います。有効/無効isSecureTextEntryでも同じ問題が発生します。
@Gal Shaharの答えは素晴らしいですが、それでも完璧ではありません。マスクされた文字は、アップルからの安全なエントリテキストで使用されたマスクされた文字と同じではありません。Unicode文字「BLACKCIRCLE」(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
}
}
Appleのおかげで、isSecureTextEntryがYESに設定されていると、ネイティブメソッドを使用する方法が見つかりませんでした。Gal Shaharの方法は、パスワードの自動入力アクセサリの表示オプションを無効にする唯一のソリューションです。しかし、それはより簡単です
Objective c
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
迅速
textField(_:shouldChangeCharactersIn:replacementString:)
委任。そして、このような単純なコードを使用します。後でtextFieldの実際のコンテンツを含むString変数を宣言します。私のものはpswdです。
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
//Thanks iOS13!!!
if(!_pswd)
{
_pswd = @"";
}
_pswd = [_pswd stringByReplacingCharactersInRange:range withString:string];
if (!buttonShowPassword.selected)
{
textField.text = [@"" stringByPaddingToLength:_pswd.length withString: @"•" startingAtIndex:0];
}
else
{
textField.text = _pswd;
}
return NO;
}
SwiftUIの場合、次のようにします。
SecureField("Password", text: "some text").disableAutocorrection(true)
textContentTypeプロパティを次のように設定してみてください.textContentType-これにより、iOS 11に、フィールドがユーザー名/パスワードのフィールドではないことが通知され、アクセサリビューが表示されなくなります。`self.passwordField.textContentType = .textContentType`のようなもの