지금은 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 는 isSecureTextEntry
속성뿐만 아니라 속성 별로도 암호 textFields를 인식하는 것으로 textContentType
보이므로 textContentType을 아무것도 설정하지 않고 secureEntry 기능을 제거하고 앱에서 보안 결함을 유발하지 않는 한이 액세서리보기를 사라지게하는 것은 실제로 불가능합니다. 그런 다음 iOS 12가 textField를 암호 textField로 인식하고이 성가신 액세서리보기를 표시하지 못하게합니다.
제 경우에는 액세서리로 인해 탭했을 때 앱이 응답하지 않는 버그가 발생했습니다 (앱 검토 프로세스에서 앱이 거부되었습니다). 그래서이 기능을 제거해야했습니다. 이 보안 기능을 포기하고 싶지 않았기 때문에 스스로 해결해야했습니다.
아이디어는 secureEntry 기능을 제거하고 수동으로 추가하는 것입니다. 작동했습니다.
다음과 같이 할 수 있습니다.
스위프트 4 웨이 :
먼저 여기에 대답 한대로 textContentType
아무것도 설정 하지 않습니다.
if #available(iOS 10.0, *) {
passwordText.textContentType = UITextContentType("")
emailText.textContentType = UITextContentType("")
}
그보다 나중에 textField 실제 콘텐츠를 포함 할 String 변수를 선언합니다.
var passwordValue = ""
textField 내용이 변경 될 때마다 호출되는 passwordTextField에 대상을 추가합니다.
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
하려면 textField 를 .no
로 설정 합니다.
passwordText.autocorrectionType = .no
그게 다야 passwordValue
로그인을 수행 데 사용하십시오.
누군가를 도울 수 있기를 바랍니다.
최신 정보
붙여 넣은 값도 포착하고 전에 추가하는 것을 잊었습니다.
사용자 이름이나 비밀번호가 아닌 콘텐츠 유형을 지정하여 기능을 비활성화 할 수 있습니다. 예를 들어 사용자가 이메일 주소를 입력해야하는 경우 다음을 사용할 수 있습니다.
usernameTextField?.textContentType = .emailAddress
ios11의 매우 간단한 접근 방식이 저에게 효과적이었습니다. iboutlet이 usernametextfield 및 passwordtextfield라고 가정합니다. 두 outlest를 보유하는 viewcontroller의 viewDidLoad () 함수에서 다음 코드를 사용하십시오.
usernametextfield.textContentType = UITextContentType("")
passwordtextfield.textContentType = UITextContentType("")
그 후에는 텍스트 필드를 탭할 때 자동 완성 액세서리 옵션이 표시되지 않습니다.
@Gal Shahar 답변에 대한 응답.
iOS 12 는 비밀번호 텍스트 필드를 isSecureTextEntry
속성 별로 인식 하지 않고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'는 필드를 비 웁니다.
목표 -C
if (@available(iOS 10, *)){
self.tfEmail.textContentType = @"";
self.tfPassword.textContentType = @"";
}
이것은 나를 위해 일했습니다.
자동 완성은 기본적으로 사용자에게 활성화됩니다. iOS는 모든 암호를 키 체인에 저장하고 앱의 키보드에서 사용할 수 있도록합니다. UITextView
그리고 UITextField
자동으로 자동 완성 암호를 고려했다. 사용자 이름이나 비밀번호가 아닌 콘텐츠 유형을 지정하여 비활성화 할 수 있지만 콘텐츠 유형 정보가 이미 키 체인에 저장되어있는 경우 퀵 바에 표시됩니다. 비어 할당하는 것이 좋습니다.UITextContentType
유형 퀵 바가 표시되지 않습니다.
예:
if #available(iOS 10.0, *) {
self.textField.textContentType = UITextContentType("")
} else {
// Fallback on earlier versions
}
textContentType
암호 텍스트 필드에 더미 를 할당하여 사용자 이름 / 암호 콤보 감지를 "끄기"할 수 있습니다 .
passwordFormField.textContentType = UITextContentType("dummy")
이렇게하면 암호 필드와 그 앞에있는 전자 메일 필드 모두에 대한 키 기호가 꺼져서 미리 정의 된 값 중 하나를 사용하지 않고 키보드 액세서리보기에 관련없는 제안이 표시되는 것을 방지 할 수 있습니다.
newPassword
UITextContentType 으로이 암호 필드에 태그를 지정합니다 . 그래도이 새로운 행동을 피하는 방법을 모르겠습니다.
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 버전을 모두 확인할 필요가 없습니다. 저는 초보자 일 뿐이므로 "최상의"답변이 아니거나 가장 효율적인 답변이 아닐 수도 있지만 나에게 가장 의미가 있습니다.
먼저 Storyboard에서 "Secure Text Entry"를 선택 취소하거나 암호 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이이 자동 채우기 기능을 계속 수정하는지 확실하지 않습니다. , 지금은 매우 버그가 많습니다.
이것은 나를 위해 일했습니다.
참고 : 암호, 암호 확인 (해당되는 경우) 및 이메일 텍스트 필드에이 코드를 입력 해보십시오. 나는 그것을 이메일 텍스트 필드에 넣지 않았고 여전히 두 개의 암호 필드에 대해 팝업되었습니다.
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: "")
}
모든 UITextField textContentType을 양식으로 설정 UITextContentType("")
하거나 .oneTimeCode
깨끗한 솔루션이 아니라고 생각 합니다. 활성화 / 비활성화는 isSecureTextEntry
여전히 동일한 문제를 제공합니다.
@Gal Shahar의 답변은 좋지만 여전히 완벽하지는 않습니다. 마스크 된 문자는 애플의 보안 입력 텍스트에 사용 된 마스크 문자와 동일하지 않습니다. 유니 코드 문자 '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
}
}
Apple 덕분에 isSecureTextEntry가 YES로 설정되었을 때 네이티브 메서드로 방법을 찾을 수 없었습니다. Gal Shahar의 방법은 암호 자동 완성 액세서리보기 옵션을 비활성화하는 유일한 솔루션입니다. 하지만 더 쉽습니다.
목표 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`과 같은 것