今のところ、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つを使用せず、キーボードアクセサリビューに無関係な提案が表示されないようにします。
newPassword
12UITextContentTypeのタグを付けています 。ただし、この新しい動作を回避する方法はわかりません。
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`のようなもの