如果我们使用多个文本字段,如何自动获取OTP

时间:2018-11-21 13:41:32

标签: ios swift uitextfield one-time-password

我知道,如果要自动获取OTP(如果使用单个文本字段),则需要使用

otpTextField.textContentType = .oneTimeCode

但是,如果我们使用多个文本字段(根据下图)

some thing like this

我们应该如何实现呢?

5 个答案:

答案 0 :(得分:4)

->从iOS 12开始,Apple将允许支持人员读取您将在iPhone设备中获得的一次性代码。您可以将文本分为四个字段并自动填充,然后手动输入otp并一一删除并移动每个文本字段。

1)self.textone最大长度4,其他textfield最大长度1

2)添加UITextFieldDelegate

enter image description here

if #available(iOS 12.0, *) {
   txtOne.textContentType = .oneTimeCode
}
self.txtOne.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
self.txtOne.becomeFirstResponder()

  @objc func textFieldDidChange(_ textField: UITextField) {
    if #available(iOS 12.0, *) {
        if textField.textContentType == UITextContentType.oneTimeCode{
            //here split the text to your four text fields
            if let otpCode = textField.text, otpCode.count > 3{
                txtOne.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 0)])
                txtTwo.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 1)])
                txtThree.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 2)])
                txtFour.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 3)])
            }
        }
     } 
  }

 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

       if (string.count == 1){
           if textField == txtOne {
               txtTwo?.becomeFirstResponder()
           }
           if textField == txtTwo {
               txtThree?.becomeFirstResponder()
           }
           if textField == txtThree {
               txtFour?.becomeFirstResponder()
           }
           if textField == txtFour {
               txtFour?.resignFirstResponder()
               textField.text? = string
                //APICall Verify OTP
               //Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(self.VerifyOTPAPI), userInfo: nil, repeats: false)
           }
           textField.text? = string
           return false
       }else{
           if textField == txtOne {
               txtOne?.becomeFirstResponder()
           }
           if textField == txtTwo {
               txtOne?.becomeFirstResponder()
           }
           if textField == txtThree {
               txtTwo?.becomeFirstResponder()
           }
           if textField == txtFour {
               txtThree?.becomeFirstResponder()
           }
           textField.text? = string
           return false
       }

   }

答案 1 :(得分:2)

如果您可以获得单个字段的自动OTP,则可以将该文本分为四个文本字段。我相信。

您可能必须使用textField的更改观察器,如下所示,

textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
func textFieldDidChange(_ textField: UITextField) {

        // here check you text field's input Type
        if textField.textContentType == UITextContentType.oneTimeCode{

            //here split the text to your four text fields

            if let otpCode = textField.text, otpCode.count > 3{

                textField.text = String(otpCode[otpCode.startIndex])
                textField1.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 1)])
                textField2.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 2)])
                textField3.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 3)])
        }
    }

}

答案 2 :(得分:1)

我所做的与@Natarajan的答案类似,但是我使用UITextFieldDelegate方法。在viewDidAppear上,您的第一个文本字段应成为第一响应者,并且类型为oneTimeCode

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {        
    // Fill your textfields here

    return true
}

答案 3 :(得分:0)

我被Firebase OneTimeCode困在6个不同的UITextField中,并设法允许OS从文本消息自动填充它,还允许用户复制和粘贴它,当然还允许用户逐个插入以非常手动但有效的方式实现shouldChangeCharactersIn:

   func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        //This lines allows the user to delete the number in the textfield.
        if string.isEmpty{
            return true
        }
        //----------------------------------------------------------------

        //This lines prevents the users from entering any type of text.
        if Int(string) == nil {
            return false
        }
        //----------------------------------------------------------------

        //This lines lets the user copy and paste the One Time Code.
        //For this code to work you need to enable subscript in Strings https://gist.github.com/JCTec/6f6bafba57373f7385619380046822a0
        if string.count == 6 {
            first.text = "\(string[0])"
            second.text = "\(string[1])"
            third.text = "\(string[2])"
            fourth.text = "\(string[3])"
            fifth.text = "\(string[4])"
            sixth.text = "\(string[5])"

            DispatchQueue.main.async {
                self.dismissKeyboard()
                self.validCode()
            }
        }
        //----------------------------------------------------------------

        //This is where the magic happens. The OS will try to insert manually the code number by number, this lines will insert all the numbers one by one in each TextField as it goes In. (The first one will go in normally and the next to follow will be inserted manually)
        if string.count == 1 {
            if (textField.text?.count ?? 0) == 1 && textField.tag == 0{
                if (second.text?.count ?? 0) == 1{
                    if (third.text?.count ?? 0) == 1{
                        if (fourth.text?.count ?? 0) == 1{
                            if (fifth.text?.count ?? 0) == 1{
                                sixth.text = string
                                DispatchQueue.main.async {
                                    self.dismissKeyboard()
                                    self.validCode()
                                }
                                return false
                            }else{
                                fifth.text = string
                                return false
                            }
                        }else{
                            fourth.text = string
                            return false
                        }
                    }else{
                        third.text = string
                        return false
                    }
                }else{
                    second.text = string
                    return false
                }
            }
        }
        //----------------------------------------------------------------


        //This lines of code will ensure you can only insert one number in each UITextField and change the user to next UITextField when function ends.
        guard let textFieldText = textField.text,
            let rangeOfTextToReplace = Range(range, in: textFieldText) else {
                return false
        }
        let substringToReplace = textFieldText[rangeOfTextToReplace]
        let count = textFieldText.count - substringToReplace.count + string.count


        if count == 1{
            if textField.tag == 0{
                DispatchQueue.main.async {
                    self.second.becomeFirstResponder()
                }

            }else if textField.tag == 1{
                DispatchQueue.main.async {
                    self.third.becomeFirstResponder()
                }

            }else if textField.tag == 2{
                DispatchQueue.main.async {
                    self.fourth.becomeFirstResponder()
                }

            }else if textField.tag == 3{
                DispatchQueue.main.async {
                    self.fifth.becomeFirstResponder()
                }

            }else if textField.tag == 4{
                DispatchQueue.main.async {
                    self.sixth.becomeFirstResponder()
                }

            }else {
                DispatchQueue.main.async {
                    self.dismissKeyboard()
                    self.validCode()
                }
            }
        }

        return count <= 1
        //----------------------------------------------------------------

    }

注意:我在此代码中使用下标字符串方法,您可以在此处获得此扩展名String+Subscript.swift

当然不要忘记将委托和.oneTimeCode分配给TextField。

textField.delegate = self
textField.textContentType = .oneTimeCode

答案 4 :(得分:-2)

更新iOS 12

Apple将允许支持人员读取您将在iPhone设备中获得的一次性密码(OTP-一次性密码)。

iOS在UITextField,UITextView和任何采用UITextInput协议的自定义视图上支持密码自动填充。系统键盘将其上的textContentType设置为.oneTimeCode

1)使用代码

singleFactorCodeTextField.textContentType = .oneTimeCode

2)使用情节提要/ XIB

在情节提要/ XIB中选择UITextField / UITextView,然后单击“属性”检查器。转到文本输入特征,单击“内容类型”,然后选择一个时间码并完成。

在设置了此UITextContentType的情况下,操作系统将自动从“消息”中检测验证码。

此外,您可以为该otp分配期望的值。

查看https://developer.apple.com/documentation/security/password_autofill/enabling_password_autofill_on_a_text_input_view的官方文档